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.

2 comments:

Cameron said...

Thanks for posting this, it was a helpful example.

Naviya Nair said...

I have read your blog its very attractive and impressive. I like it your blog.

Java Online Training Java EE Online Training Java EE Online Training Java 8 online training Core Java 8 online training

Java Online Training from India Java Online Training from India Core Java Training Online Core Java Training Online Java Training InstitutesJava Training Institutes

Post a Comment