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?
As far as I understand your problem is what you want a result of sqlSessionFactory()
to be a SqlSessionFactory
(for use in other methods), but you have to return SqlSessionFactoryBean
from a @Bean
-annotated method in order to trigger Spring callbacks.
It can be solved with the following workaround:
@Configuration
public class AppConfig {
@Bean(name = "sqlSessionFactory")
public SqlSessionFactoryBean sqlSessionFactoryBean() { ... }
// FactoryBean is hidden behind this method
public SqlSessionFactory sqlSessionFactory() {
try {
return sqlSessionFactoryBean().getObject();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
@Bean
public AnotherBean anotherBean() {
return new AnotherBean(sqlSessionFactory());
}
}
The point is that calls to @Bean
-annotated methods are intercepted by an aspect which performs initialization of the beans being returned (FactoryBean
in your case), so that call to sqlSessionFactoryBean()
in sqlSessionFactory()
returns a fully initialized FactoryBean
.