How to programmatically define Spring beans

The Spring framework is well know both for its powerful architecture and its often barely tolerated XML configuration syntax.So there are cases where you would like to take advantage of Spring features (Dependency Injection, scope management, AOP, Transaction Management) in a set of beans without having to declare all of them in XML. This is particularly the case where you need to define a non-trivial number of similar beans (e.g. DAOs, backing beans in a JSF application, etc.).

In practice, we want to be able to write something like

ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
SampleService s = (SampleService) context.getBean("sampleService");

(or the equivalent code in a webapp or servlet with a WebApplicationContext) so that s get initialized by Spring in the right scope without actually declaring sampleService in application.xml.

Thanks to Spring modularity, there are several ways of achieving this:

  • define the bean through annotations;
  • define a custom BeanDefinitionReader that reads from a property/configuration file instead of XML;
  • define the bean programmatically.

I will now describe how to do it with the third approach. With most kinds of ApplicationContexts, it is possible to use the BeanDefinitionRegistry interface to dynamically and programmatically declare beans:

BeanDefinition definition = new RootBeanDefinition(SampleService.class);
//optionally configure all bean properties, like scope, prototype/singleton, etc
context.registerBeanDefinition("sampleService", definition);

This allows you to manually add a bean definition to the context.

In order to fully automatize the configuration, we can define a BeanFactoryPostProcessor that is automatically invoked after the standard xml file is read, being thus able to automatically add more bean definitions. The bean definitions can be for instance created by scanning classes for custom annotations, scanning custom configuration files, or any other custom criteria.

The following example will create a bean for each *.service file in the config directory

import java.io.IOException;
import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
 import org.springframework.beans.factory.support.RootBeanDefinition;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
 import org.springframework.context.ResourceLoaderAware;
 import org.springframework.core.io.Resource;
 import org.springframework.core.io.ResourceLoader;
public class AutoBeanDeclarer implements BeanFactoryPostProcessor, ApplicationContextAware
 {
      private ApplicationContext mainContext;
public void postProcessBeanFactory(ConfigurableListableBeanFactory context)
        throws BeansException
{
BeanDefinitionRegistry registry = ((BeanDefinitionRegistry)context);
Resource[] fileList = null;

 fileList = mainContext.getResources("config/*.service");
for (Resource file : fileList)
{
System.out.println("File found: "+file.getFilename());
BeanDefinition definition = new RootBeanDefinition(SampleServiceImpl.class);
registry.registerBeanDefinition(file.getFilename(), definition);
}
public void setApplicationContext(ApplicationContext mainContext)
 {
      this.mainContext = mainContext;
}
}

The BeanFactoryPostProcessor can then be simply added to the main application.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!-- note: no definition of SampleService  -->
<bean id="autoConfigurer" class="AutoBeanDeclarer"/>
</beans>

Spring will then automatically activate the PostProcessor after reading all configuration files.

A possible use in a web application could be that of automatically defining a bean for each html page/component. More examples will appear in future posts…

Thank you for your time! I hope you enjoyed this post. You can find more materials on Spring on the JUG Genova website.

Tags:

3 Responses to “How to programmatically define Spring beans”

  1. Web 2.0 Announcer Says:

    How to programmatically define Spring beans…

    […]The Spring framework is well know both for its powerful architecture and its often barely tolerated XML configuration syntax.&#xD;
    &#xD;
    So there are cases where you would like to take advantage of Spring features (Dependency Injection, …

  2. Blog » Blog Archive » Carlo Bonamico’s weblog " Blog Archive " How to programmatically Says:

    […] ãã¥ã¼ã¨ã¼ã¯ã&reg… wrote an interesting post today on Carlo Bonamico’s weblog &quot; Blog Archive &quot; How to programmaticallyHere’s a quick excerpt […]

  3. napyfab:blog» Blog Archive » links for 2008-01-25 Says:

    […] Carlo Bonamico’s weblog » Blog Archive » How to programmatically define Spring beans (tags: spring definition programming programmatically development framework springframework bean) […]