What is the correct way to use factory beans in @Configuration
classes?
Suppose I have the following for SessionFactory
:
@Bean
public AnnotationSessionFactoryBean sessionFactory() {
AnnotationSessionFactoryBean factory = new AnnotationSessionFactoryBean();
// set up properties etc.
return factory;
}
Right now this method returns a bean factory which does not implement SessionFactory
. If I use it in another bean with @Autowired
as SessionFactory
, it works just fine and obtains it from bean factory:
@Controller
public class MyController {
@Autowired SessionFactory sessionFactory;
// ...
}
I guess that's OK.
However, it becomes an issue if I want to use the SessionFactory
in the same configuration class:
@Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager man = new HibernateTransactionManager();
// Ideal - doesn't work because sessionFactory() return type doesn't match:
// SessionFactory sessionFactory = sessionFactory();
// Is this one correct?
// SessionFactory sessionFactory = (SessionFactory) sessionFactory().getObject();
man.setSessionFactory(sessionFactory);
return man;
}
What is The Right Way to implement this kind of dependency?
@Configuration
approach is still relatively fresh and it has some rough edges. Factory beans are one of them. So the is no Right Way, at least I am not aware of any. Maybe future Spring releases will handles this case somehow. For now, this is my preferred way:
@Bean
public AnnotationSessionFactoryBean sessionFactoryBean() {
AnnotationSessionFactoryBean factory = new AnnotationSessionFactoryBean();
// set up properties etc.
return factory;
}
@Bean
public SessionFactory sessionFactory() {
return (SessionFactory) sessionFactoryBean().getObject();
}
And use sessionFactory()
method whenever needed. If you want to call the sessionFactoryBean().getObject()
several times for some reason (e.g. when FactoryBean
does not return singletons), remember to use @Scope
annotation. Otherwise Spring will make sure sessionFactory()
is called only once and cache the result.
Spring is intelligent enough to perform all required initialization after calling @Bean
method and before returning the bean itself. So InitializingBean
, DisposableBean
, @PostConstruct
, etc. are all recognized and treated properly. In fact, I was always finding calling afterPropertiesSet
a bit of a hack, because it is the container responsibility.
Also there is a second method advised in Spring Datastore Document - Reference Documentation, which at first sight looks a bit inconsistent, but works great:
@Resource
private Mongo mongo;
@Bean
MongoFactoryBean mongo() {
return new MongoFactoryBean();
}
So factory is created using @Bean
method but the bean created by the factory can be obtained using autowired field. Clever.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With