Saturday, August 17, 2013

Spring: injecting properties file values into Spring managed beans

In this post, we'll go through 3 different ways to configure (XML based) a Spring application, to inject properties file values into its managed beans.

Method 1: <util:properties> schema based configuration element

In the Spring configuration file, import the spring-util schema, then use the <util:properties> element to register a bean of type java.util.properties. This element expects both an id, and a location attribute. The former is necessary to determine from which Properties bean the value we want to inject comes from, while the latter is expected to define which properties file is to be loaded in the Properties bean.

Once a Properties bean has been defined, its values can be injected into Spring managed beans with the following annotation: @Value("#{properties_bean_id[property_name]}")

Example:

Content of the prop1.properties file:


message1=Message from prop1.properties


Spring configuration: 


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
  http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">

 <context:component-scan base-package="example1" />

 <util:properties id="propSource" location="classpath:/sample-properties/prop1.properties" />
</beans>

Property value injection into Spring managed bean:

@Value("#{propSource[message1]}")



Method 2: <context:property-placeholder> schema based configuration element


This time, in the Spring configuration file, import the spring-context schema, then use the <context:property-placeholder> element to register a bean of type org.springframework.beans.factory.config.PropertyPlaceholderConfigurer. Just like in the previous method, this element expects the location attribute that specifies the properties file to load.

To retrieve a property value, use the syntax as follows: ${property_name}

Example:

Content of the prop2.properties file:

message2=Message from prop2.properties

Spring configuration:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

 <context:component-scan base-package="example2" />

 <context:property-placeholder location="classpath:/sample-properties/prop2.properties"/>
</beans>



Property value injection into Spring managed bean:

@Value("${message2}")


Method 3: registering bean of type PropertyPlaceholderConfigurer


In this last method, we just have to explicitly register a bean of type org.springframework.beans.factory.config.PropertyPlaceholderConfigurer. Then, we'll need to specify a location property that determines the properties file to be loaded.

The syntax used to retrieve property values is exactly the same as method 2, that is: ${property_name}

Example:

Content of prop3.properties file:

message3=Message from prop3.properties

Spring configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

 <context:component-scan base-package="example3" />
 
 <bean id="propSource" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="location" value="classpath:/sample-properties/prop3.properties" />
 </bean>
</beans>



Property value injection into Spring managed bean:

@Value("${message3}")

Extra example: defining multiple PropertiesPlaceholderConfigurer (PPC) beans + PPC with multiple properties files




 
 
 
  
  
 
 
 
  
   
    classpath:/sample-properties/prop2.properties
    classpath:/sample-properties/prop3.properties
   
  
 

To define a PropertyPlaceholderConfigurer bean to load multiples properties files, we use the locations property and set its value to a list of properties files.

Another thing we must pay attention to, is when we are defining multiple PropertyPlaceholderConfigurer beans within a same Spring context (in this example, we're defining 2 of them). In this case, we need to specify the ignoreUnresolvablePlaceholders property in the first PPC bean(s) with the value true. Otherwise, the application context will fail to load as Spring, at bean build time, tries to inject a value that resides in a properties file that is to be loaded in another PPC bean. 

More precisely, in this example: the Component4 class expects value injection from prop1.properties, prop2.properties and prop3.properties files. When trying to inject the values from prop2.properties and prop3.properties, the placeholders could not be resolved yet as they depends on the second PPC bean. Therefore, using the ignoreUnresolvablePlaceholders property on the first PPC bean will prevent exceptions from being thrown, and we'll just wait for another PPC bean to be able to inject these values.

Working source code

A sample project to test the different methods we've just went through is available here