FactoryBeans and the annotation-based configuration in Spring 3.0

Andrew Newdigate picture Andrew Newdigate · Apr 4, 2011 · Viewed 45.9k times · Source

Spring provides the FactoryBean interface to allow non-trivial initialisation of beans. The framework provides many implementations of factory beans and -- when using Spring's XML config -- factory beans are easy to use.

However, in Spring 3.0, I can't find a satisfactory way of using factory beans with the annotation-based configuration (née JavaConfig).

Obviously, I could manually instantiate the factory bean and set any required properties myself, like so:

@Configuration
public class AppConfig {

...

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource());
        factory.setAnotherProperty(anotherProperty());

        return factory.getObject();
    }

However, this would fail if the FactoryBean implemented any Spring-specific callback interfaces, like InitializingBean, ApplicationContextAware, BeanClassLoaderAware, or @PostConstruct for example. I also need to inspect the FactoryBean, find out what callback interfaces it implements, then implement this functionality myself by calling setApplicationContext, afterPropertiesSet() etc.

This feels awkward and back-to-front to me: application-developers should not have to implement the callbacks of the IOC container.

Does anyone know of a better solution to using FactoryBeans from Spring Annotation configs?

Answer

tsachev picture tsachev · Jan 26, 2012

I think that this is best solved when you rely on auto-wiring. If you are using Java configuration for the beans, this would like:

@Bean
MyFactoryBean myFactory()
{ 
    // this is a spring FactoryBean for MyBean
    // i.e. something that implements FactoryBean<MyBean>
    return new MyFactoryBean();
}

@Bean
MyOtherBean myOther(final MyBean myBean)
{
    return new MyOtherBean(myBean);
}

So Spring will inject for us the MyBean instance returned by the myFactory().getObject() as it does with XML configuration.

This should also work if you are using @Inject/@Autowire in your @Component/@Service etc classes.