Configuration with property placeholder
The runtime configuration settings are most likely needed in your Spring configuration class. That's the place were the beans should be properly instantiated.
1 /** 2 * Core Application Configuration. 3 */ 4 @Configuration 5 @PropertySource("${myAppProperties:classpath:myApp.properties}") 6 public class AppConfig { 7 8 @Bean 9 public SampleBean sampleBean(@Value("${httpProxy:}") String httpProxy, 10 @Value("${httpProxyPort:0}") int httpProxyPort, 11 @Value("${httpConnectionTimeout:30000}") int httpConnectionTimeout, 12 @Value("${httpReceiveTimeout:60000}") int httpReceiveTimeout, 13 @Value("${targetServiceUrl}") String targetServiceUrl) { 14 return new SampleBean(httpProxy, httpProxyPort, httpConnectionTimeout, 15 httpReceiveTimeout, targetServiceUrl); 16 } 17 18 @Bean 19 public static PropertySourcesPlaceholderConfigurer properties() { 20 PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer(); 21 pspc.setNullValue(""); // handle empty Strings as null value 22 return pspc; 23 } 24 25 }
To inject a runtime configuration value into a bean the @Value annotation is used together with a property placeholder (${<propertyName>:<defaultValue>}).The interesting parts of this configuration class are:
- method parameter injection is used to set the runtime properties
(see @Value annotation in sampleBean) - a default value for a property is provided whenever possible
(the default value is provided after the ':' in the property placeholder) - a PropertySource annotation is used to add a property file to the Spring Enviroment
- a PropertySourcePlaceholderConfigurer is instantiated to resolve the properties against the Spring Environment
The location of the PropertySource is declared as a placeholder itself
${myAppProperties:classpath:myApp.properties}
which means that the value of the myAppProperties system property will be used as a PropertySource resource or - if this is not defined - the classpath:myApp.properties file per default.
This setup now allows to put all properties in a property file and "activate" the file using e.g.
-DmyAppProperties=file:c:/<configDir>/myApp.properties
If this property is not set, the default myApp.properties file which is provided in the classpath of the application (Maven src/main/resources directory) will be used. The content of this file looks like this
1 ## ---------------------------------------------------------------------------- 2 ## Example application property file. 3 ## All application runtime configuration properties are documented here. 4 ## 5 ## Required properties with no default value must be configured in a special 6 ## property file or by setting corresponding system properties. The resource 7 ## reference to a special property file can be set with the system property 8 ## 'myAppProperties' e.g. like this: 9 ## 10 ## -DmyAppProperties=file:c:/<confidDir>/myApp.properties 11 ## 12 ## ---------------------------------------------------------------------------- 13 14 # http proxy server 15 # -- optional 16 #httpProxyServer= 17 18 # http proxy port 19 # -- optional 20 #httpProxyServer= 21 22 # http connection timeout in milliseconds 23 # -- required, default: 30000 24 #httpConnectionTimeout= 25 26 # http receive timeout in milliseconds 27 # -- required, default: 30000 28 #httpReceiveTimeout= 29 30 # the URL of the service wee need to access 31 # -- required 32 #targetServiceUrl=
You see that no properties are set in here (everything is commented out). In my example application this file is mostly used for documentation purposes and to provide a default file so that it is not required to set the myAppProperties system property on startup.
If the default property file is picked up, the settings of course have to be provided in another way. The nearby solution is to provide them as system properties. As only one property is really required in the example it will be enough to specify
-DtargetServiceUrl=http//foo.bar
during application startup. All other properties will be instantiated with their default values defined in the configuration class.
Starting the application
The newest trend to start Spring Applications is to use Spring Boot. A very simple Main class that uses Spring Boot to start the application looks like this:
1 /** 2 * The main class to start the application. 3 */ 4 public class Main { 5 6 /** 7 * Start the application. This will just configure the Spring Application 8 * Context and print the runtime configuration setting. 9 * 10 * @param args 11 */ 12 public static void main(String[] args) { 13 SpringApplication app = new SpringApplication(AppConfig.class); 14 app.setShowBanner(false); 15 ApplicationContext ctx = app.run(args); 16 17 SampleBean sampleBean = ctx.getBean(SampleBean.class); 18 System.out.println(sampleBean.toString()); 19 } 20 21 }
With Spring Boot it is now even possible to use program arguments to configure the application like this
java Main --targetServiceUrl=http://foo.bar
It is also possible to mix the usage of system properties and program arguments.
Here are some example invocations of the "application" with the output of the configuration settings.
# configuration via system properties
> java -cp lib\*; -DtargetServiceUrl=http://foo.bar Main
SampleBean{httpProxy=null, httpProxyPort=0, httpConnectionTimeout=30000, httpReceiveTimeout=60000, targetServiceUrl=http://foo.bar}
# configuration via program arguments
> java -cp lib\*; Main --targetServiceUrl=http://lorem.ipsum
SampleBean{httpProxy=null, httpProxyPort=0, httpConnectionTimeout=30000, httpReceiveTimeout=60000, targetServiceUrl=http://lorem.ipsum}
# mixed system property / program arguments configuration
> java -cp lib\*; -DhttpConnectionTimeout=15000 Main --targetServiceUrl=http://lorem.ipsum
SampleBean{httpProxy=null, httpProxyPort=0, httpConnectionTimeout=15000, httpReceiveTimeout=60000, targetServiceUrl=http://lorem.ipsum}
Conclusion
The Spring framework offers wide possibilities to support runtime configuration for an application. This includes the possibilities to
- provide default configuration values whenever possible (convention over configuration)
- provide runtime settings in a property file
- provide runtime settings as system properties
- provide runtime settings as program arguments
Further reading:
- Sample project of this post on GitHub
- Spring blog post about Unified Property Management
- Spring Boot Reference Guide