Thursday, November 1, 2012

Spring PropertyPlaceholderConfigurer Tip

With the increased scrutiny on preferring to keep passwords in files and not as part of the source code, our reliance on PropertyPlaceholderConfigurer (PPC) has greatly increased. An important property of a PPC is the ignoreUnresolvablePlaceholders which is by default set to false. Setting this to false means that if any placeholders being passed to it were not resolved by it, it throws an exception and the entire context load fails. With the existence of multiple PPC's in a spring context (many of our own plus a few from all the transitive contexts we load), it helps to understand the interplay between them. Ideally every modules' that defines a PPC should necessarily have it's ignoreUnresolvablePlaceholders to true - and most do it as it will cause a context failure on loading. However, one may argue that the topmost context may need to know if all properties from all contexts were correctly resolved. By setting the ignoreUnresolvablePlaceholders to true, you may end up loading the context but having placeholders unresolved. The order in which the different PPC's are consulted is determined by the order property. However, if it is not defined, it defaults to Integer.MAX_VALUE. If order is not defined in any of the PPC's, the order is slightly non-deterministic but will mostly correspond to the order in which they are defined. The reason I say mostly is because Spring can choose to eagerly initialize beans to resolve circular dependencies. This is not limited to PPC's but also encompasses our vanilla beans referring other beans. This has been a topic that I believe we don't really pay a lot of attention to - but bites when you are least expecting. Anyway, there is a spring ticket out there to also have an "order" for vanilla beans as well. Coming back to ensuring that the context load is successful only when all placeholders have been able to be resolved - you can define an empty PPC that will act as the signaller for any unresolved placeholders. We will not define any locations for this PPC, and will have an order that is the highest among all - say Integer.MAX_VALUE with the default value of ignoreUnresolvablePlaceholders as false. Since this is the last guy that will get triggered, any unresolved placeholders will be flagged and context load stopped. Ofcourse this depends on the premise that the contexts (from different jars) that the topmost context loads will not have PPC's that are defined without order (defaulting to Integer.MAX_VALUE) and hence will not get loaded after the empty PPC in the topmost context.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="ppc1"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>file:///tmp/p1.properties</value>
            </list>
        </property>
        <property name="ignoreUnresolvablePlaceholders" value="true" />
        <property name="order" value="10000" />
    </bean>

    <bean id="ppc2"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>file:///tmp/p2.properties</value>
            </list>
        </property>
        <property name="ignoreUnresolvablePlaceholders" value="true" />
        <property name="order" value="10001" />
    </bean>

    <bean id="overallPPC"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="order" value="20000" />
    </bean>

    <bean id="simpleBean" class="com.kilo.SimpleBean">
        <property name="property1" value="${com.kilo.property1}" />
        <property name="property2" value="${com.kilo.property2}" />
        <property name="property3" value="${com.kilo.property3}" />
        <property name="property4" value="${com.kilo.property4}" />
    </bean>

</beans>

So all you nice people out there giving out their jars with spring contexts to others, please ensure that your set an order of your PPC other than the default of Integer.MAX_VALUE. A good rule of thumb could be to use 10000-90000 for our own non-toplevel PPC.

References:

1. http://tarlogonjava.blogspot.in/2009/02/tips-regarding-springs.html
2. Sample setup available at https://github.com/kilokahn/spring-testers/tree/master/spring-ppc-tester


No comments:

Post a Comment