Is it possible to have common xml configuration for all Cache provider vendors for jsr107 - caching

We need to have common XML configuration parameters(like timetolive) for Jcache configuration.
We are using EhCache for Development and might be using some other Jsr107 compliant cache provider, like Infinispan, in other environment.
is it possible to have single configuration file being used by both Caching provider, and we need to change only some parameters, if required, for different environment?
Is it ok to define these properties in properties file and use them to initialize Cache managers based on Profile?
I went through jsr107 documentation but didn't find common xml caching attributes.
Technology : Spring boot 1.2.3, Java 7

It really depends on what you need to use. JCache exposes a Configuration and MutableConfiguration classes that you can use to configure some settings.
Spring Boot 1.3 (about to be released) has a complete JCache integration; when you add a JSR-107 provider in your project, Spring Boot will automatically create a CacheManager for you. If you define a bean of type JCacheManagerCustomizer, it will be invoked to customize the cache manager before the application starts servicing requests.
For instance, this is a very basic configuration that changes the expiration policy:
#SpringBootApplication
#EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public JCacheManagerCustomizer cacheManagerCustomizer() {
return cm -> {
MutableConfiguration<Object, Object> configuration = new MutableConfiguration<>()
.setExpiryPolicyFactory(CreatedExpiryPolicy
.factoryOf(Duration.ONE_HOUR));
cm.createCache("foo", configuration);
};
}
}

JSR-107 does not specify anything with regards to external configuration - xml, properties, you name it.
As such any externalized configuration solution will have to be provided by your code or a framework like [Spring][1].
[1]: See Stéphane Nicoll's answer

Related

Implement multi-tenanted application with Keycloak and springboot

When we use 'KeycloakSpringBootConfigResolver' for reading the keycloak configuration from Spring Boot properties file instead of keycloak.json.
Now there are guidelines to implement a multi-tenant application using keycloak by overriding 'KeycloakConfigResolver' as specified in http://www.keycloak.org/docs/2.3/securing_apps_guide/topics/oidc/java/multi-tenancy.html.
The steps defined here can only be used with keycloak.json.
How can we adapt this to a Spring Boot application such that keycloak properties are read from the Spring Boot properties file and multi-tenancy is achieved.
You can access the keycloak config you secified in your application.yaml (or application.properties) if you inject org.keycloak.representations.adapters.config.AdapterConfig into your component.
#Component
public class MyKeycloakConfigResolver implements KeycloakConfigResolver {
private final AdapterConfig keycloakConfig;
public MyKeycloakConfigResolver(org.keycloak.representations.adapters.config.AdapterConfig keycloakConfig) {
this.keycloakConfig = keycloakConfig;
}
#Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
// make a defensive copy before changing the config
AdapterConfig currentConfig = new AdapterConfig();
BeanUtils.copyProperties(keycloakConfig, currentConfig);
// changes stuff here for example compute the realm
return KeycloakDeploymentBuilder.build(currentConfig);
}
}
After several trials, the only feasible option for spring boot is to have
Multiple instances of the spring boot application running with different spring 'profiles'.
Each application instance can have its own keycloak properties (as it is under different profiles) including the realm.
The challenge is to have an upgrade path for all instances for version upgrades/bug fixes, but I guess there are multiple strategies already implemented (not part of this discussion)
there is a ticket regarding this problem: https://issues.jboss.org/browse/KEYCLOAK-4139?_sscc=t
Comments for that ticket also talk about possible workarounds intervening in servlet setup of the service used (Tomcat/Undertow/Jetty), which you could try.
Note that the documentation you linked in your first comment is super outdated!

Where does spring boot configure default application.properties

By default Spring Boot will automatically load properties from classpath:/application.properties
I want to know where is this auto configuration source code.
I want to exclude from my app.
IE: #EnableAutoConfiguration(exclude=XXXXAutoconfiguration.class)
The reason is:
Because I cannot override the default application.properties by an external property using #PropertySource
#SpringBootApplication
#ComponentScan(basePackages = {"com.test.green.ws"})
#PropertySource(value = {"classpath:/application.properties", "file:/opt/green-ws/application.properties"})
public class GreenWSApplication {
public static void main(String[] args) {
SpringApplication.run(GreenWSApplication.class, args);
}
}
There are many ways to override property keys without disabling the whole externalized configuration feature; and that's actually the goal.
You can see here the order the properties are considered in. For example, you can add that external properties file in a config folder right next to the packaged JAR, or even configure the file location yourself.
Now if you really want to disable all of that (and the Boot team strongly suggests not to do that), you can register your own EnvironmentPostProcessor (see here) and remove PropertySources from MutablePropertySources, which you can fetch with configurableEnvironment. getPropertySources().
There's no easier way to do that because:
this comes really early in the application init phase, before auto-configurations
this is not something you should do, as it will have many side effects

Reload property value when external property file changes ,spring boot

I am using spring boot, and I have two external properties files, so that I can easily change its value.
But I hope spring app will reload the changed value when it is updated, just like reading from files. Since property file is easy enough to meet my need, I hope I don' nessarily need a db or file.
I use two different ways to load property value, code sample will like:
#RestController
public class Prop1Controller{
#Value("${prop1}")
private String prop1;
#RequestMapping(value="/prop1",method = RequestMethod.GET)
public String getProp() {
return prop1;
}
}
#RestController
public class Prop2Controller{
#Autowired
private Environment env;
#RequestMapping(value="/prop2/{sysId}",method = RequestMethod.GET)
public String prop2(#PathVariable String sysId) {
return env.getProperty("prop2."+sysId);
}
}
I will boot my application with
-Dspring.config.location=conf/my.properties
I'm afraid you will need to restart Spring context.
I think the only way to achieve your need is to enable spring-cloud. There is a refresh endpoint /refresh which refreshes the context and beans.
I'm not quite sure if you need a spring-cloud-config-server (its a microservice and very easy to build) where your config is stored(Git or svn). Or if its also useable just by the application.properties file in the application.
Here you can find the doc to the refresh scope and spring cloud.
You should be able to use Spring Cloud for that
Add this as a dependency
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.2.RELEASE'
And then use #RefreshScope annotation
A Spring #Bean that is marked as #RefreshScope will get special treatment when there is a configuration change. This addresses the problem of stateful beans that only get their configuration injected when they are initialized. For instance if a DataSource has open connections when the database URL is changed via the Environment, we probably want the holders of those connections to be able to complete what they are doing. Then the next time someone borrows a connection from the pool he gets one with the new URL.
Also relevant if you have Spring Actuator
For a Spring Boot Actuator application there are some additional management endpoints:
POST to
/env to update the Environment and rebind #ConfigurationProperties and log levels
/refresh for re-loading the boot strap context and refreshing the #RefreshScope beans
Spring Cloud Doc
(1) Spring Cloud's RestartEndPoint
You may use the RestartEndPoint: Programatically restart Spring Boot application / Refresh Spring Context
RestartEndPoint is an Actuator EndPoint, bundled with spring-cloud-context.
However, RestartEndPoint will not monitor for file changes, you'll have to handle that yourself.
(2) devtools
I don't know if this is for a production application or not. You may hack devtools a little to do what you want.
Take a look at this other answer I wrote for another question: Force enable spring-boot DevTools when running Jar
Devtools monitors for file changes:
Applications that use spring-boot-devtools will automatically restart
whenever files on the classpath change.
Technically, devtools is built to only work within an IDE. With the hack, it also works when launched from a jar. However, I may not do that for a real production application, you decide if it fits your needs.
I know this is a old thread, but it will help someone in future.
You can use a scheduler to periodically refresh properties.
//MyApplication.java
#EnableScheduling
//application.properties
management.endpoint.refresh.enabled = true
//ContextRefreshConfig.java
#Autowired
private RefreshEndpoint refreshEndpoint;
#Scheduled(fixedDelay = 60000, initialDelay = 10000)
public Collection<String> refreshContext() {
final Collection<String> properties = refreshEndpoint.refresh();
LOGGER.log(Level.INFO, "Refreshed Properties {0}", properties);
return properties;
}
//add spring-cloud-starter to the pom file.
Attribues annotated with #Value is refreshed if the bean is annotated with #RefreshScope.
Configurations annotated with #ConfigurationProperties is refreshed without #RefreshScope.
Hope this will help.
You can follow the ContextRefresher.refresh() code implements.
public synchronized Set<String> refresh() {
Map<String, Object> before = extract(
this.context.getEnvironment().getPropertySources());
addConfigFilesToEnvironment();
Set<String> keys = changes(before,
extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(context, keys));
this.scope.refreshAll();
return keys;
}

Best approach to configuration management in spring framework for a project with multiple modules?

I have a project setup something like this:
-common-lib (common lib to included by multiple services)
-event-lib (spring framework 4 (read IOC) library for our event buffer. I want to embed the prod configuration within the app so consumers can use it without configuring it.
-serviceA (depends on event-lib, springboot application)
-serviceB (depends on event-lib, spring framework application)
I've been struggling on how to manage configuration in a Java-annotated way.
In the example below (running in the event library as a spring framework 4 project):
I couldn't get the PropertySource to honor the enviornment's spring.profiles.active
The environment wouldn't set an active profile even though -Dspring.profiles.active="dev" was specified)
#Configuration
#ComponentScan(basePackages = "com.*")
#PropertySource("classpath:events-{$spring.profiles.active}.properties")
public class EventConfiguration {
#Inject
private ConfigurableApplicationContext ctx;
#Inject
private Environment environment;
#Value("${events.asset-processing-queue}")
private String assetProcessingEventQueue;
}
It didn't make much sense to me, since multiple profiles could be activated at once (and that approach to referencing files is dependent on having only 1 set active).
Ideally, I am trying to find a solution that:
Uses either yaml or a combination of properties files for all the environment properties needed
Has some sort of intelligent hierarchy of what properties should be loaded. E.g. if I specify a property in my shared lib, honor it unless the consumer overrides it with their own value.
Can work in a spring framework 4 or spring boot app (we do some stuff with AWS lambda and dont want the spring boot overhead)
Relies only on java annotation and flat files for the properties. (Prefer to avoid XML).
Here's how we did it:
#PropertySource("classpath:/${env}.config.properties")
public class Application implements RequestHandler<Request, Object> {
#Override
public Object handleRequest(Request request, Context awsContext) {
ExecutionEnvironment env = getEnvironment(awsContext.getFunctionName());
System.setProperty("env", env.toString());
This respects the environment property.

Automatic configuration reinitialization in Spring

In Log4j, there is a feature wherein the system can be initialized to do a configure and watch with an interval. This allows for the log4j system to reload its properties whenever the property file is changed. Does the spring framework have such a Configuration Observer facility wherein the Configuration is reloaded when it changed. The Configuration that needs reloading is not the Springs's applicationContext.xml but various other configuration files that are initialized using the Spring initialization beans.
I found a utility that does something similar to Log4J here. It's basically an extension to PropertyPlaceholderConfigurer that reloads properties when they change.
AFAIK Spring does not provide such a utility. However there is a 3rd party tool, JRebel that enables you to update an entire web application (including the Spring configuration) without requiring a server restart.
A free trial is available, and the purchase price is fairly inexpensive.
I would be extra cautious with reloading spring application context.
What do you expect to happen with singleton beans? If an object has a reference to singleton bean, should it be updated?
I develop using JRebel and I would be very wary of expecting it to refresh your configuration. Works fine with Java, not with Spring though.
If you would like to add context, I have done that in the following way :
public class ApplicationContextUtil
{
static String[] configFiles = {"applicationContextParent.xml"};
private static ApplicationContext context = null;
static
{
context = new ClassPathXmlApplicationContext ( configFiles );
}
public static void addContext( String[] newConfigFiles )
{
// add the new context to the previous context
ApplicationContext newContext = new ClassPathXmlApplicationContext ( newConfigFiles, context );
context = newContext;
}
public static ApplicationContext getApplicationContext ()
{
// return the context
return context;
}
}
This is your context provider class. For details, you can look at my blog

Resources