spring configurations

In larger projects you often end up with some settings which should be stored in configuration files. These are mostly settings that won’t change much during the development lifecycle but can change based on which machine the application is running on. A good example for this is the database connect string that the application should connect on. A developer machine can connect to a mysql instance where as the production machine can connect to a large scale oracle database. When deploying the application to production, the deployers should then always check to see if these settings are still corrrect. This can cause a lot of errors in a real time envrionment.

When using maven, it is possible to capture these settings in profiles, but the builders have to remember to build the application using the correct profile, so that the correct settings can be used.

When using spring this can be done even simpler using the PropertyPlaceholderConfigurer bean. Most developers will likely have used this class, but there are some hidden gems in that class that not all developers are aware of.

Using the PropertyPlaceholderConfigurer is done by specifiying it in the context.xml that your application uses, for instance:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="database.properties"/>
</bean>

In your database.properties file you can set the key-value pairs of the parameters that you want to substitute, e.g.
db.url=com.mysql.jdbc.Driver
db.connect=jdbc:mysql://localhost:3306/test
db.username=testuser
db.password=testuser

Then in the rest of your xml you can use these values by referring to these parameters, e.g.
<bean id="datasource" ...>
<property name="url" value="${db.url}"/>
</bean>

Most developers are already familiar with this class and its usage so far, but you can do some more magic with this class. Especially for the problem of using multiple environment settings as described before, this class can be very convenient. The solution is to have multiple configuration files, where the last one loaded will overwrite the previous ones. If you make sure that the last one is your own properties file, then you are set. This leads to the following configuration:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/services.properties</value>
<value>classpath:/db.properties</value>
<value>file:${user.home}/db.properties</value>-->
</list>
</property>
</bean>

What this configuration does is that it will first load the services.properties in the root of the classpath (hence the classpath:/ notation). After that has been loaded the db.properties will be loaded. Then the file in the user.home directory for db.properties will be loaded, and in here lies the trick. Since this parameter is already parameterized (${user.home} is a system wide parameter), the system will try to load the db.properties that are defined in the user’s home directory. And thus if there does exists such a file in the directory, and it has also the defined parameters as defined in services.properties or db.properties, these user.home settings will override the default properties. In this way each developer can have it’s own database and username password without interfering with the production version. And even better, the production version can contain the username and password overwrites such that other users can not see what those are.

However this can still fail if the file is not present in the user.home directory. Therefor you should also configure this bean as follows:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/services.properties</value>
<value>classpath:/db.properties</value>
<value>file:${user.home}/db.properties</value>-->
</list>
</property>
<property name="ignoreResourceNotFound" value="true"/>
</bean>

Now the system will not fail anymore if the resources defined can not be found.

When using the keys, you can also add default values for when the values are not found in the properties. This can be done by adding a seperator character in the key with a default value. Default value for this separator is the “:” character, so usage of the keys will look like this:
<bean id="datasource" ...>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username:testuser}"/>
</bean>

It is also possible to replace the “:” character seperator with another key, since the “:” can be used inside urls as well. It is also possible to add the default properties itself as properties, but I prefer using a default properties file for this.