在我看来,最自然的方式是干预 EntityListener 的实例化过程。这种方式在 Hibernate 5.3 之前的版本和 5.3 之后的版本中显着不同。
1)在 5.3 之前的 Hibernate 版本 org.hibernate.jpa.event.spi.jpa.ListenerFactory
中,负责 EntityListener 的实例化。如果您提供自己的基于 CDI 的javax.enterprise.inject.spi.BeanManager
. CDI 接口(对于 Spring DI 世界来说是不必要的)冗长,但实现 Spring BeanFactory 支持的 CDI Bean 管理器并不难。
@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
}
类型相关的实现SpringBeanType<T>
将如下所示:
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
}
现在,唯一剩下的就是将我们BeanManager
在属性名下的实现注入到 Hibernate 配置设置中javax.persistence.bean.manager
。可能有很多方法可以做到这一点,让我只介绍其中一种:
@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;
}
}
请记住,有两件事必须是 Spring bean: a) SpringCdiBeanManager
,以便BeanFactory
可以注入/自动装配到它;b)您的 EntityListener 类,以便该行return beanFactory.getBean(clazz);
成功。
2)正如@AdrianShum 非常正确地指出的那样,在Hibernate 5.3 及更高版本中,Spring bean 的事情要容易得多。从 5.3 Hibernate 开始使用org.hibernate.resource.beans.container.spi.BeanContainer
概念,并且有其现成的 Spring Beans 实现,org.springframework.orm.hibernate5.SpringBeanContainer
. 在这种情况下,只需遵循其javadoc即可。