如何在 EntityListeners 中注入 EntityManager
Posted
技术标签:
【中文标题】如何在 EntityListeners 中注入 EntityManager【英文标题】:How to inject EntityManager in EntityListeners 【发布时间】:2014-04-05 22:40:35 【问题描述】:我需要在 EntityListener 类中注入 EntityManager,以便我可以对其执行 CRUD 操作。
POJO:
@Entity
@EntityListner(AuditLogging.class)
class User
//Getter / setter of properties
AuditLogging(Listner 类)
public class AuditInterceptor
@PersistenceContext
EntityManager entityManager;
public void setEntityManager(EntityManager entityManager)
this.entityManager = entityManager;
@PrePersist
public void prePersist(Object obj)
// Here I want to use ENTITY manager object so that I can perform CRUD operation
// with prePersist coming object.
entityManager.unwrap(Session.class).save(obj);
// But I am getting NULL POINTER EXCEPTION for entity manager object
JDBC-CONFIg.xml
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="packagesToScan" value="com.XXXXX.entity" />
<property name="jpaProperties">
</bean>
<!-- Datasource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="$jdbc.driver.classname" />
<property name="jdbcUrl" value="$jdbc.url" />
</bean>
<!-- transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
EntityListener 不由任何容器管理。EntityListener 由 JPA 实例化,因此 Spring 没有机会注入 EntityManager。 我的问题是,我们如何在 EntityListener 类中注入 EntityManager 以便我可以对其执行 CRUD 操作???
【问题讨论】:
【参考方案1】:我在尝试使用 EntityListeners 为实体创建历史记录时遇到了类似的问题。
为了解决这个问题,我用静态方法创建了实用程序类BeanUtil
来获取 bean,并使用这个实用程序类在我的 Entitylistener 类中获取 bean
@Service
public class BeanUtil implements ApplicationContextAware
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
context = applicationContext;
public static <T> T getBean(Class<T> beanClass)
return context.getBean(beanClass);
现在我们可以调用 BeanUtil.getBean() 来获取任意类型的 bean
public class FileEntityListener
@PrePersist
public void prePersist(File target)
perform(target, INSERTED);
@Transactional(MANDATORY)
private void perform(File target, Action action)
EntityManager entityManager = BeanUtil.getBean(EntityManager.class);
entityManager.persist(new FileHistory(target, action));
我们可以使用这个BeanUtil
类从任何地方获取任何spring 托管bean,要了解更多信息,您可以阅读我的文章JPA Auditing: Persisting Audit Logs Automatically using EntityListeners。
【讨论】:
【参考方案2】:无论如何,我通过从 EntityManagerFactory
bean 中获取 entityManager 引用来完成此操作,该 bean 在我的 jdbc-config.xml
中配置。但这又不是我想要的。我想和@PersistenceContext
一起工作。
@Autowired
EntityManagerFactory entityManagerFactory;
private static EntityManager entityManager;
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory)
entityManager=entityManagerFactory.createEntityManager();
this.entityManagerFactory = entityManagerFactory;
我们需要牢记以下几点:
-
我们不能将
EntityManager
注入EntityListener
(通过
@PersistenceContext
)。 EntityListener
不受任何
容器
@PersistenceContext
类不能是静态的。所以我们不能
在类加载时获取实例。
EntityListener 是
由 JPA 实例化,因此 Spring 没有机会
注入EntityManager
【讨论】:
【参考方案3】:嗯,我想到的第一个解决方案有点“hack”,但应该可以。
public class AuditInterceptor
static setEntityManager emf;
@Autowired
public void setEntityManagerFactory(EntityManager emf)
AuditInterceptor.emf = emf;
@PrePersist
public void prePersist(Object obj)
EntityManager entityManager = emf.getEntityManager();
// Here I want to use ENTITY manager object so that I can perform CRUD operation
// with prePersist coming object.
entityManager.unwrap(Session.class).save(obj);
// But I am getting NULL POINTER EXCEPTION for entity manager object
在您的代码内部使用EntityManager entityManager = emf.getEntityManager()
将您的 AuditInterceptor
声明为 spring bean(@Component
使用组件扫描或将 AuditorInterceptor
定义为 bean)
【讨论】:
@PersistenceContext 不能变成静态的。 我的示例不再使用@PersistenceContext。谷歌也把我带到了这个post【参考方案4】:我使用 ThreadLocal 来传递包含 EntityManager 的 Spring 应用程序上下文。虽然我不确定它是否安全 Is it safe to pass in the Spring Application Context into a ThreadLocal associated with a request? 但到目前为止它对我有用。
【讨论】:
以上是关于如何在 EntityListeners 中注入 EntityManager的主要内容,如果未能解决你的问题,请参考以下文章
java.lang.ClassNotFoundException: javax.persistence.EntityListeners
Caused by: java.lang.ClassNotFoundException: javax.persistence.EntityListeners