如何获取Spring Data JPA自动创建的EntityListener单例引用?
问题:Spring Data JPA实体监听器双实例问题及获取正确引用的方法
Spring Data JPA会为标注@EntityListeners(EntityListenerClass.class)的实体类自动实例化EntityListener。我需要在Controller中访问这个自动实例化的监听器并调用其方法,因此希望获取它的引用。
示例代码如下:
实体类
@Entity @EntityListeners(EntLi.class) public class MyEntity { ... }
EntityListener类
@Service public class EntLi { public EntLi(){ System.out.printf("EntLi instanciated %s\n", this); new Exception().printStackTrace(); } ... }
CRUD仓库
public interface MyEntRepo extends CrudRepository<MyEntity, MyEntKeyType> { }
Controller类
public class Ctrl{ @Autowired private MyEntRepo repo; @Autowired private EntLi listener; ... }
疑问:为何会生成两个不同的EntLi实例?如何正确获取Spring Data JPA实例化MyEntRepo时创建的EntLi实例引用?
原因分析:为什么出现两个实例?
- 你给
EntLi标注了@Service注解,Spring容器会自动创建并管理一个单例实例,这就是Controller中@Autowired注入的那个。 - Spring Data JPA底层依赖JPA持久化提供者(比如Hibernate),默认情况下,它会直接通过反射创建一个新的
EntLi实例,不会走Spring的Bean管理流程,这就导致了第二个实例的产生。
解决方案:获取同一实例的方法
要让JPA复用Spring容器管理的EntLi实例,需要让JPA通过Spring容器获取监听器,具体步骤如下:
让JPA使用Spring的Bean工厂
- 如果是Spring Boot项目,直接在
application.properties或application.yml中添加配置(Spring Boot 2.1及以上版本支持):spring.jpa.properties.javax.persistence.bean.manager=org.springframework.beans.factory.BeanFactory - 或者通过配置类自定义
EntityManagerFactory:@Configuration public class JpaConfig { @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory( EntityManagerFactoryBuilder builder, DataSource dataSource, ApplicationContext applicationContext) { LocalContainerEntityManagerFactoryBean em = builder .dataSource(dataSource) .packages("你的实体类所在包路径") // 替换为实际包路径 .persistenceUnit("default") .build(); // 配置JPA使用Spring的Bean工厂获取监听器 em.setJpaPropertyMap(Collections.singletonMap( "javax.persistence.bean.manager", applicationContext.getAutowireCapableBeanFactory() )); return em; } }
- 如果是Spring Boot项目,直接在
确保
EntLi被Spring管理
保留@Service注解(或者替换为@Component),让Spring创建并维护EntLi的单例实例。这样JPA就会复用这个实例,不会再自己创建新的。验证结果
之后Controller中@Autowired注入的EntLi实例,就和JPA处理实体时使用的是同一个了,直接调用方法即可。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

