The most natural way is, in my opinion, to intervene into the process of instantiating of EntityListener.
This way significantly differs in Hibernate pre-5.3 versions and post-5.3 ones.
1) In Hibernate versions earlier than 5.3 org.hibernate.jpa.event.spi.jpa.ListenerFactory
is responsible for EntityListener instantiation. The instantiation of this factory can be intercepted if you provide your own CDI-based javax.enterprise.inject.spi.BeanManager
. The CDI interfaces are (unnecessary for Spring DI world) verbose, but it's not difficult to implement Spring BeanFactory-backed CDI Bean manager.
@Component
public class SpringCdiBeanManager implements BeanManager {
@Autowired
private BeanFactory beanFactory;
@Override
public <T> AnnotatedType<T> createAnnotatedType(Class<T> type) {
return new SpringBeanType<T>(beanFactory, type);
}
@Override
public <T> InjectionTarget<T> createInjectionTarget(AnnotatedType<T> type) {
return (InjectionTarget<T>) type;
}
...
// have empty implementation for other methods
}
and the implementation of type-dependent SpringBeanType<T>
will look like this:
public class SpringBeanType <T> implements AnnotatedType<T>, InjectionTarget<T>{
private BeanFactory beanFactory;
private Class<T> clazz;
public SpringBeanType(BeanFactory beanFactory, Class<T> clazz) {
this.beanFactory = beanFactory;
this.clazz = clazz;
}
@Override
public T produce(CreationalContext<T> ctx) {
return beanFactory.getBean(clazz);
}
...
// have empty implementation for other methods
}
Now, the only thing left is to inject into Hibernate Configuration Settings our implementation of BeanManager
under a property name javax.persistence.bean.manager
. There are, probably, many ways to do so, let me bring just one of them:
@Configuration
public class HibernateConfig {
@Autowired
private SpringCdiBeanManager beanManager;
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter(){
@Override
public Map<String, Object> getJpaPropertyMap(){
Map<String, Object> jpaPropertyMap = super.getJpaPropertyMap();
jpaPropertyMap.put("javax.persistence.bean.manager", beanManager);
return jpaPropertyMap;
}
};
// ...
return jpaVendorAdapter;
}
}
Just remember that two things have to be Spring beans:
a) SpringCdiBeanManager
, so that BeanFactory
could be injected/autowired to it;
b) your EntityListener class, so that line return beanFactory.getBean(clazz);
will be successful.
2) In Hibernate versions 5.3 and later things are much easier for Spring beans, as @AdrianShum very correctly pointed out. Since 5.3 Hibernate uses org.hibernate.resource.beans.container.spi.BeanContainer
concept and there is its ready-to-use implementation for Spring Beans, org.springframework.orm.hibernate5.SpringBeanContainer
. In this case, just follow its javadoc.