Mar
12
2005

Configuration management with Spring

For every project we have a staging environment that is almost always pretty much identical to the production environment. Of course you can’t completely mimick the production environment since systems we’re integrating with are not available (in which case they’re mocked) or located in a different place. We’re doing a lot Spring-based apps and some of the features Spring offers are really useful when distinguishing between a local environment, a staging environment and the final production environment. The following discusses the possibilities you have for setting up a Spring ApplicationContext to be able to deploy it to different environments without having to change the context itself.

PropertyPlaceHolderConfigurer

Spring offers two beans that allow you to externalize some of the properties in an ApplicationContext. The first and most often used one is the PropertyPlaceholderConfigurer. This bean allows you to include ${xxxyyyzzz} tokens in your application context and have them resolved at run-time (when the application context is loaded) from an external Properties file for example. An example would be the following:

<bean id='salesForceConnection' 
    class='icatch.salesforce.SalesForceConnectionImpl'
    singleton='false' 
    init-method='init' destroy-method='close'>
  <property name='url'>
    <value>${salesforce.url}</value>
  </property>
</bean>

The connection to the Salesforce service we’re integrating with is not mentioned in the context itself. Instead we are going to provide a separate Properties file and include it there. When deploying the application on the staging environment, we do not want to connect to the live Salesforce environment, but to the development edition instead. This offers the same features so we can still test everything. So based on the environment, we’re placing a different properties file in a pre-defined location and the application itself doesn’t need to change.

# staging.properties
salesforce.url=\
  https://na1-api.salesforce.com/services/Soap/c/3.0
 
#live.properties
salesforce.url=\
  https://emea.salesforce.com/services/Soap/c/2.5

Of course we still have to tell Spring where to find the properties it needs use when replacing the tokens. This is where the so-called BeanFactoryPostProcessor comes in. A post-processor is automatically executed after a context has fully finished loading all its bean definitions. This doesn’t mean any beans have been instantiated yet! The post-processor is allowed to inspect the application context and make changes as he wishes. One of those post-processor is the PropertyPlaceholderConfigurer. Configure it using the code snippet below. As you can see, we’ve put a Properties file in a pre-defined location and give it to the Spring placeholder configurer using the location property.

<bean class='org.spr....config.PropertyPlaceholderConfigurer'>
  <propert name='location'>
    <value>/etc/icatch/sfconnection.properties</value>
  
</propert></bean>

PropertyOverrideConfigurer

The example above shows an ApplicationContext with tokens that are replaced at run-time. Another option is to have default values in your context and have a PropertyOverrideConfigurer override those. This way you don’t always have to mention a configurer in your context and provide default values for development purposes. This would look something like the following:

<bean id='salesForceConnection'
    class='icatch.salesforce.SalesForceConnectionImpl'
    singleton='false' 
    init-method='init' destroy-method='close'>
  <property name='url'>
    <value>${salesforce.url}</value>
  </property>
  <property name='username'>
    <value>blabbering</value>
  </property>
  <property name='password'>
    <value>blabbering</value>
  </property>
  <property name='sessionTimeoutMS'>
    <value>5400000</value> <!-- 1,5 hour -->
  </property>
</bean>
#live-override.properties
salesForceConnection.username=realusername
salesForceConnection.password=realpassword

Choosing beans using a configurer

(overriding bean references)

One other nifty thing you can do using placeholder and override configurers is referencing a different bean based on a properties file. This feature is not really documented anywhere but can be handy sometimes. The configurers as they exist now only override and replace property values. In other words, they’re not capable of overriding and replacing complete bean definitions. The configurers are however able to override and replace bean references. This can be quite handy when you have more complex requirements and cannot do with simply replacing a property value:

<beans>
  <bean class='org.spr....config.PropertyPlaceholderConfigurer'>
    <property name='properties'>
      <props>
        <prop key='connection.name'>connectionOne</prop>
      </props>
    </property>
  </bean>
 
  <bean id='service' class='ServiceObject'>
    <property name='salesForceConnection'>
      <ref bean='${connection.name}'/>
    </property>
  </bean>
 
  <bean id='connectionOne' class='SuperConnection'>
    <!-- other properties -->
  </bean>
 
  <bean id='connectionTwo' class='NotSoSuperConnection'>
    <!-- other properties -->
  </bean>
 
</beans>

Remember, usually one would split such a context in three files: one containing connectionTwo, one containing connectionOne and the other containing the service object. Based on what environment you’re in you would load a certain combinations of contexts. This is the way to go forward when selecting a data source implementation but the drawback here is that you need to override the bean itself. You cannot override the bean reference here. Using a PropertyPlaceholderConfigurer or PropertyOverrideConfigurer you can do that.

The location of your properties files

Then there is of course the issue of how to manage the different configurations. We usually have a configuration module in CVS where we keep directories for all different environments (one for staging, one for testing, one for production). Deploying a new version mean we have do the following:

  • Deploy the new war file
  • Overwrite the configuration directory with the directory we’ve pulled from CVS, specific to the current environment

So in case of the above examples, we’d have the following directory structure:

   +-- staging
           - placeholder.properties
           - override.properties
   +-- production
           - placeholder.properties
           - override.properties
Written by Alef in: Java-related, Spring |

34 Comments »

  • Seth Ladd says:

    We do something very similar. We include, in every project, a dev.properties, qa.properties, and a prod.properties. Based on the ant command we give (ant dev, ant qa, or ant prod) we pull out that properties file and put it in our .war file. What’s nice is that individual developers can have their own configs (seth.properties), and just run ‘ant seth’ to build for seth’s configuration.

  • [...] terview Question (v2) Spring Configuration Management Here is an article which offers a good tip on the way to use property files to override some of the [...]

  • haiko says:

    Alef,

    Can I ask you something about configuration management of Spring. Can I use the JndiObjectFactoryBean to refer to a datasource that is already registered by a J2EE-container. My problem is that a DataSource will be configured by a administrator and that i just know the name. Where do i set the
    property for the name and which property is this (is this ??

    Maybe i see you soon. I work at Sogeti and heared that you people are giving seminars to us.

    Gr. Haiko

  • Alef says:

    Yes, that’s the exact purpose of the JndiObjectFactoryBean. The jndiName property (I believe) is what you need to use to set the jndi name. Something like this:

    class="org.sprfr.jndi.JndiObjectFactoryBean">


    regards,
    Alef

  • Fang says:

    We use the file system implementation of the JNDI service com.sun.jndi.fscontext.RefFSContextFactory, and the PROVIDER_URL is
    “file:/data/admin/jndi”. How should the JndiObjectFactoryBean be specified?

    would give me an error message:
    Can’t resolve reference to bean ‘file:/data/admin/jndi/jdbc/mytestdb’ while setting property ‘jndiName’; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException.

  • Keith says:

    Alef, in your article, you state that when breaking out the bean definitions into multiple files (something I need to do), you can’t override the bean references. Is this because the beans are definted across multiple files? You then state that uUsing a PropertyPlaceholderConfigurer or PropertyOverrideConfigurer you can do that (I assume this means you can override the bean references). Can you provide some more direction on how to do this? Thanks.

  • Hi Keith,

    I have limited access to internet at the moment. I’ll be at the office next week and hope not to forget to reply. Could you please remind me if I don’t?

    thanks,
    alef

  • Stefan says:

    Hi Alef,

    your entry really helped me – thanks a lot!

    I wonder if it is possible to define several different PropertyPlaceHolderConfigurer bean instances in one context?
    I tried (even with adding the attribute “singleton=false”) but the first bean of this special class seems to override all others…

    Kind regards, Stefan

  • Stefan says:

    Hi again,

    after reading the source code of the PropertyPlaceHolderConfigurer class it seems as if it is not possible because the first bean factory post processor if this type throws an exception if it cannot resolve ALL properties it finds.

    That’s a pity.

    When different parts of an application want to externalize their configuration, they have to add their property file into the argument list of one central PropertyPlaceHolderConfigurer.

    But you can’t have it all… ;-)

  • Mike Cunneen says:

    Stefan,

    You can do this using the locations property of the PropertyPlaceHolderConfigurer, like this:

    classpath:file1.properties
    classpath:file2.properties

    This worked for me in Spring 2.

  • Mike Cunneen says:

    OK, it escaped the quoted tags as invalid HTML tags despite me using the <code> tag.

    Second attempt:

    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
    <list>
    <value>classpath:xapi.properties</value>
    <value>classpath:XapiServiceAuthenticator.properties</value>
    </list>
    </property>
    </bean>

  • Mike Cunneen says:

    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
    <list>
    <value>classpath:xapi.properties</value>
    <value>classpath:XapiServiceAuthenticator.properties</value>
    </list>
    </property>
    </bean>

  • Steve says:

    Is there a way of overriding a collection? I have a list I need to override.

    Thanks,

    Steven

  • Nathan Ward says:

    What directory are your .properties files in when deployed as part of a web application (i.e. in a .war file)? I’ve been asked to put them in WEB-INF/config directory on my current project. So, I can’t use classpath: in the locations list of the PropertyPlaceholderConfigurer. So, I specify /WEB-INF/config/acegi-security.properties (for example). This works fine except when I try to use the same Spring XML configuration files from a unit test. The other developers want to have Tomcat point to their project directory under the Eclipse workspace. So, the development environment has WebRoot/WEB-INF/config directory. Since, the Spring XML file specifies /WEB-INF/config, Eclipse and Ant expect a directory of WEB-INF/config under my top-level project directory.

    Nathan

  • Nathan Ward says:

    I figured out how to specify a path to property files in WEB-INF/config in the PropertyPlaceholderConfigurer location that works for both the web application as well for unit tests. The Ant style path can be specified: **/*/config/acegi-security.properties. For unit tests, I use a FilesystemXmlApplicationContext with paths of like WebRoot/WEB-INF/config/applicationContext.xml. The xml file has a PropertyPlaceholderConfigurer with the path as shown above.

  • Alef says:

    Nathan,

    yes, the fact that the PropertyPlaceholderConfigurer support Ant-style expressions is pretty neat.

    I think I should start rewriting this blog post by the way; it has a lot of comments already and might need an update, also since we released Spring 2.0.

  • Clint says:

    Maybe it’s just me, but your XML markup examples are hidden as the browser tries to render them as HTML. Try surrounding your markup with <xmp> tags.

  • Abhijit says:

    Hello,

    In our project we have to load property file at starting of application server and put those values in JNDI Context.

    I tried to do so in spring using following

    Using this it loads a property file but I am not able to see property values inside the file. How can I be able to achieve this in Spring MVC
    is it a right way to do so?
    Or if you have some idea about it will please help me in this.

    Thanks & Regards

    Abhijit

  • Ulises says:

    Hello, I’ve multiple PropertyPlaceholderConfigurer beans because in the application I’m working we add to the main Spring Context several context for different modules and I’m having problem with this because the context doesn’t find the placeholders but it doesn’t show problems in finding the .properties files. Does anybody kwnow something or had the same problem?
    Thanks in advance!

    Ulises

  • Peter Ciuffetti says:

    Ive had success overriding bean definitions just by specifiying a bean with the same id in a context file loaded after the master definitions.

    If your web.xml has something like…

    contextConfigLocation

    classpath:app-defaults-spring.xml
    classpath*:app-override-spring.xml

    …then you can define a bean in app-override-spring.xml placed anywhere in the web app’s classpath, like in WEB-INF/classes. If the file is missing or not found, then the default definition will apply. Otherwise the defintion in app-override.xml will apply.

  • Peter Ciuffetti says:

    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    classpath:app-defaults-spring.xml
    classpath*:app-override-spring.xml
    </param-value>
    </context-param>

  • [...] The first solutions you can get the detailed from here. [...]

  • David says:

    I’m fairly new to Spring but I have a project that’s very similar to the situation described above. There is ALOT of code that uses this one particular database object. Currently there are multiple files with the datasource information contained in each. I’m trying to find out if it is possible to specify a placeholder by checking for a system property and if it isn’t available using a default value.

    Like I said, I’m very new to Spring, less than 1 week old, so I apologize if this is very basic.

  • Eric says:

    Thanks for the post! I realize I could have found the information I needed in the Spring book at the spring sight, but this concise how-to write up gave me what I needed to know more quickly.

  • tqmk yozugl nrdf rcdpgbxhs syejv dirz iaft

  • Gabriel Falkenberg says:

    Hi, it IS possible to have several PropertyPlaceHolderConfigurers. You just have to understand how the ordering affects the values and you must set the property ignoreUnresolvablePlaceholders to true on all but the PropertyPlaceHolderConfigurer loaded last (the one with the highest order-value).

    The way it works is that the values set by the first PropertyPlaceHolderConfigurer cannot be overridden by PropertyPlaceHolderConfigurer loaded later.

    Working like this makes it possible to spit the configuration in several contexts and let every context have its own PropertyPlaceHolderConfigurers which is responsible for the placeholders in its own context file.

  • Matias says:

    Hi,
    What about replacing values in constructor arguments? is it possible?

  • Alef says:

    Yes certainly that possible. Just use the ${} format in the constructor-arg’s value attribute and you’re good to go.

  • Andri says:

    Hi Alef,

    I try to use PropertyPlaceholderConfigurer and I put my properties file in WEB-INF folder, but I get error FileNotFoundException. The properties name is spring.properties and when I run my application on tomcat, spring.properties can’t be found.
    Below is my configuration of spring-config.xml:

    /WEB-INF/spring.properties

    And below is the code to create instance of bean factory:

    BeanFactory factory = new ClassPathXmlApplicationContext(”/config/spring-config.xml”);

    Do you know how to solve my problem?
    Thanks

  • Alef says:

    Hmm, the comments don’t seem to allow XML…

    Anyway, your issues relates to you instantiating a ClassPathXmlApplicationContext. This context is only capable of reading resources from the classpath or from the file system. The default is the classpath and if you want to read stuff from the filesystem, you’d have to prefix your resource string with file:

    You want to read resources from the /WEB-INF directory. This is done through the servlet context and as said, the ClassPathXmlApplicationContext can’t read stuff from the ServletContext.

    Therefore what you’d have to do is instantiate a XmlWebApplicationContext and pass it the classpath:config/spring-config.xml string. The default for this ApplicationContext is to read from WEB-INF (throught he servlet context) so if in turn using this context you want to read from the classpath, you’d have to prefix your resource strings with classpath: (or file: for files from the filesystem).

    Another way of doing it, is using a ContextLoaderListener. This element can be configured in web.xml (it’s a listener) and loads up an app ctx for you and puts it in the servlet context. Have a look at the reference manual for more info.

    cheers,
    Alef

  • [...] first solutions you can get the detailed from here. For the 3rd solution, you can subclass XmlWebApplicationContext and override the [...]

  • Raj says:

    Hi Alef,

    The article gives a good reading.

    I have an application level properties file configured using PropertyPlaceholderConfigurer. I use a ‘classpath:’ prefix to refer the properties file outside the .war application. For some reason, the properties file is not getting loaded during application deployment and throws a FileNotFoundException. And this happens only in a Linux Environment under Weblogic 8.1 server. The same works fine in a Windows box.

    My bean configuration in applicationContext.xml goes like this…
    [code]

    classpath:app.properties

    [/code]

    And it throws the following exception….
    [code][/code]

    Any ideas why it does not work in a Linux env. ?

  • Raj says:

    sorry, something got messed up with ‘code’ tags.. trying to paste it again…

    User defined listener org.springframework.web.context.ContextLoaderListener failed: org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: class path resource [app.properties] cannot be opened because it does not exist.

RSS feed for comments on this post. TrackBack URL


Leave a Reply

Powered by WordPress | Theme: Aeros 2.0 by TheBuckmaker.com