Thursday, December 2, 2010

Dynamic Spring Beans using BeanFactoryPostProcessor

Recently we came on an interesting problem with our Spring XML files: in some situations we always have to create a bean in an entirely predictable manner. For example, to accomplish X you add a file Y to directory Z, then setup a bean thusly. A new chap coming onto the project pointed out that this felt like boilerplate code and as boilerplate code is not fun I decided to try to eliminate it.

A little investigation turned up a variety of alternatives, ranging from rewriting the XML files on app start prior to Spring initialization to writing some code that did a little introspection and created the beans on the fly. These beans aren't entirely dynamic, they are implied by other aspects of the project (existence of certain files in our case). These "implied beans" need to be referenced by manually configured beans so they have to be created during Spring bean loading process somehow. That is, we must be able to do this:
<bean id="myManualBean" class="...">
  <property name="myProperty" ref="anImpliedBean"/>
</bean>
<!-- 'anImpliedBean' will never be explicitly declared!! -->
This was outside what I'd done with Spring before but I figured a custom BeanFactory might do it? Well ... probably, but it looked like it would be fairly painful! However, Spring also has the perfect interface for this job: BeanFactoryPostProcessor. When Spring encounters a BeanFactoryPostProcessor it will call into it and allow it to modify the beans in postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory). In practice this works out to something like this:

In the Spring beans xml file:
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    
    <!-- Our BeanFactoryPostProcessor; it will register 'anImpliedBean' -->
    <bean class="our.package.for.ImplicitBeanCreator">
        <!-- can set pptys of the BeanFactoryPostProcessor if desired -->
    </bean>

    <bean id="myManualBean" class="...">
        <!-- note the ref to a bean not declared manually! It's like magic! -->
        <property name="myPpty" ref="anImpliedBean" />
    </bean>

    <!-- many lines of implied beans deleted == less xml hell! -->
</beans>
In Java:
public class ImplicitBeanCreator implements BeanFactoryPostProcessor {

 @Override
 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
   throws BeansException {
  //examine our environment (in our case the filesystem) to work out what beans are 'implied'
  //create them, such as by creating an instance and calling beanFactory.registerSingleton(name, object)
 }
}
Obviously this isn't something you need everyday but when it lets you avoid hand-coding swaths of completely boilerplate beans it's a wonderful thing!

Examples are all based on Spring 2.5.6.SEC01.

4 comments:

Cameron said...

Thanks for posting this, it was a helpful example.

Teer Update said...

Thank you for a giving a all information will good title..
How to find the latest and upcoming teer result online updates.
Juwai Teer Result
Get information regarding Shilong Teer Result
Teer Result

Juliana petar said...

Trade FX At Home On Your PC: tradeatf Is A Forex Trading Company. The Company States That You Can Make On Average 80 – 300 Pips Per Trade. tradeatf States That It Is Simple And Easy To Get Started.

Unknown said...

포천콜걸
포천콜걸
울진콜걸
당진콜걸
서산콜걸
여주콜걸
울릉도콜걸
여주콜걸

Post a Comment