Sunday, December 28, 2014

Properties overriding in Spring

    Encapsulation can be applied not only to classes. It can also be applied to properties but in slightly different flavor. From my standpoint encapsulation and convention over configuration are two important factors which determine the robustness of the solution.
I like to have a bunch of default properties for development purposes. I keep them in properties files which land in JARs that are eventually stored inside app.war/WEB-INF/lib. However, different properties are necessary for different environments (e.g. JDBC related properties, pool sizes, endpoint URLs, etc.). What is more, on PROD environments the properties are usually managed by different people - Operations Team. Because of that fact, I like to expose as little as possible. I start with reasonable defaults and then I allow to override some of these defaults. Let's consider the following code:
@Configuration
public class PropertyLoader {
 
 @Value("${my.property}")
 private String myProperty;
 
 public static void main(String[] args) {
  AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(PropertyLoader.class);
  System.out.println(ctx.getBean(PropertyLoader.class).getMyProperty());
 }
 
 public String getMyProperty() {
  return myProperty;
 }
 
 @Bean
 public static PropertySourcesPlaceholderConfigurer  propertyConfig() {
  PropertySourcesPlaceholderConfigurer  propertyConfig = new PropertySourcesPlaceholderConfigurer();
  // the order of Locations is important here
  propertyConfig.setLocations(new ClassPathResource("default.properties"), 
                              new ClassPathResource("override.properties"));
  propertyConfig.setIgnoreResourceNotFound(true);
  return propertyConfig;
 }
}
and the following module structure:


The content of the default.properties file is:
my.property = MyDefaultValue
The result of the main method execution is:
MyDefaultValue 
It seems we have some default property value stored within property file. Then we can add one more property file:
with the following content:
my.property = MyOverridenValue
and the result of the main method execution is now:
MyOverridenValue
It is enough that override.properties file appears in the classpath. In the distribution WAR file we have default.properties only and override.properties can be specified outside WAR file - we just need to modify the classpath. If you use Tomcat you can add to tomcat/bin/setenv.sh:
CLASSPATH=/opt/folder-with-overriden-properties
This approach follows encapsulation (only necessary properties are exposed) and convention over configuration (reasonable default values are specified) principles.

P.S. This is the last post in 2014. Happy New Year and stay tuned for the upcoming entries in 2015!

1 comment :