之前一直以为 Hibernate
独立于 Spring
, Hibernate
相关的拦截器、监听器都不能注入 Spring
容器对象,最近发现这个观点是错误的。
Hibernate
可以注入 Spring
容器对象,只是 repository
的创建顺序原因,使得对象注入失败。
User
实体:
@Entity @EntityListeners(PasswordEncodeListener.class) public class User { }
实体监听器:
@Component public class PasswordEncodeListener { @Autowired private UserRepository repository; @Autowired private JdbcTemplate jdbcTemplate; @Autowired private UserService userService; @Autowired private NoRepoService noRepoService; @PrePersist public void encode(User user) { System.out.println(repository); System.out.println(jdbcTemplate); System.out.println(userService); System.out.println(noRepoService); } }
执行保存用户的方法,打印结果:
null null null null
所以之前得出了错误的结论,认为 Hibernate
独立于 Spring
,无法使用 Spring
容器内的对象。
修改监听器,去除对仓库的依赖,包括去除直接依赖仓库的 UserRepository
与间接依赖仓库的 UserService
。
@Component public class PasswordEncodeListener { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private NoRepoService noRepoService; @PrePersist public void encode(User user) { System.out.println(jdbcTemplate); System.out.println(noRepoService); } }
再执行保存用户的方法,结果如下:
org.springframework.jdbc.core.JdbcTemplate@7e9f2c32 club.yunzhi.jpa.service.NoRepoServiceImpl@3976ebfa
更新之前的错误观点:
Hibernate
的监听器、拦截器并不是独立于 Spring
的,而是因为如果直接或间接依赖了仓库,因为创建的顺序问题,会导致所有对象注入失败。如果不依赖于仓库,对象可以注入成功。
所以在 Hibernate
内操作数据库就有了两种方案:
第一种就是我们过去的 ApplicationContextHolder
,静态方法获取 context
,手动获取仓库对象。
第二种方案就是基于这次的新发现,可以注入 JdbcTemplate
,进行数据库的操作。
虽然我总结的错误结论并不影响日常的使用,但是认为还是有必要进行纠正,大家以后都会是优秀的技术员、架构师,不希望因为我的一个错误结论,让大家在以后成长的道路上遇到困难。