Tuesday, March 15, 2011

Spring Config with Multiple PropertyPlaceholderConfigurer(s)

The project I'm involved with is using the PropertyPlaceholderConfigurer feature of Spring to manage properties. This is convenient as it allows you to load properties from the file system, but fallback to default properties if the file does not exist. For example, use defaults in your development environment, but override the properties in QA and production.

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" id="propertyConfigurer">
        <property name="properties">
            <props>
                <prop key="hibernate.connection.url">jdbc:mysql://localhost/database</prop>
                <prop key="hibernate.connection.username">username</prop>
                <prop key="hibernate.connection.password">password</prop>
            </props>
        </property>
        
        <property name="locations">
            <list>
                <value>file:/app/hibernate.properties</value>
            </list>
        </property>
        
        <property name="ignoreResourceNotFound" value="true">
    </property>
</bean>

This was working excellently until I introduced another PropertyPlaceholderConfigurer in a different JAR. I started getting Spring exceptions on startup and the context would not load: BeanDefinitionStoreException: Invalid bean definition with name name.

After a fair amount of sleuthing, I found the solution on the Spring forums. The PropertyPlaceholderConfigurer that loads first must have the "order" property, with a "low" number". Additional PropertyPlaceholderConfigurer should have a higher "order":

<property name="order" value="100"/> 

And the ignoreUnresolvablePlaceholders property must be set to true:

<property name="ignoreUnresolvablePlaceholders" value="true"/>

The other PropertyPlaceholderConfigurer needs to be updated as well. It needs a higher "order":

<property name="order" value="200"/>

And set ignoreUnresolvablePlaceholders to false, or omit it as false is the default:

<property name="ignoreUnresolvablePlaceholders" value="false"/>

Now I can import my properties and no collisions:

<import resource="classpath*:myProps.xml"></import>

Here's the Spring Forum thread and the credit goes to user pukomuko.  Interesting that the one Spring expert on the thread didn't have the solution.

1 comment:

  1. Nice job.
    But you also need to give distinct ids to both PropertyPlaceholderConfigurer, in order to avoid one being re-written by the other
    ;-)

    ReplyDelete