H2 Trigger Bean无法注入Repository的原因及解决办法
问题描述
需求:将TableTestRepo注入到实现Trigger的MyTrigger Bean中,在数据插入时执行相关逻辑。
问题:依赖注入在此处失效,其他场景下正常;调试发现注入的Repo为NULL,构造函数注入会因空值抛出异常;使用@Order控制Bean创建优先级也无效果。
相关代码:
@Component public class MyTrigger implements Trigger { @Autowired TableTestRepo tableTestRepo; @Override public void init(Connection connection, String s, String s1, String s2, boolean b, int i) throws SQLException { Trigger.super.init(connection, s, s1, s2, b, i); } @Override public void fire(Connection connection, Object[] objects, Object[] objects1) throws SQLException { //logic } @Override public void close() throws SQLException { Trigger.super.close(); } @Override public void remove() throws SQLException { Trigger.super.remove(); } } @Repository public interface TableTestRepo extends JpaRepository<TableTestEntity,Long> { }
问题原因
核心问题在于Hibernate的Trigger实例并非由Spring容器管理:
Trigger是Hibernate提供的数据库触发器回调组件,实例由Hibernate自身在初始化数据库触发器时创建,完全脱离Spring的Bean生命周期。- 因此Spring无法识别这个实例,
@Autowired、构造函数注入等Spring依赖注入机制对它完全不起作用,调整@Order也毫无意义——因为Spring根本没参与这个实例的创建过程。
解决方案
提供两种可行的解决思路:
思路1:通过Spring上下文手动获取Bean
借助Spring的ApplicationContext手动获取所需的Bean,绕过Hibernate实例化的限制:
- 实现上下文持有类,保存Spring容器上下文:
@Component public class ApplicationContextHolder 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); } }
- 修改
MyTrigger,在init方法中获取Repo实例:
public class MyTrigger implements Trigger { private TableTestRepo tableTestRepo; @Override public void init(Connection connection, String s, String s1, String s2, boolean b, int i) throws SQLException { Trigger.super.init(connection, s, s1, s2, b, i); // 从Spring上下文获取Bean this.tableTestRepo = ApplicationContextHolder.getBean(TableTestRepo.class); } @Override public void fire(Connection connection, Object[] objects, Object[] objects1) throws SQLException { // 此处可正常使用tableTestRepo执行逻辑 // tableTestRepo.xxx(); } // 其他方法保持不变 }
注意:此时MyTrigger上的@Component可以去掉,因为它不再是Spring管理的Bean。
思路2:改用Spring管理的Hibernate EventListener
放弃使用Hibernate的Trigger,改用Spring可以管理的Hibernate事件监听器,这样就能正常使用依赖注入:
示例实现插入后的事件监听器:
@Component public class TableTestInsertListener { @Autowired private TableTestRepo tableTestRepo; @EventListener public void handlePostInsert(PostInsertEvent event) { // 判断当前触发事件的实体是否是目标实体 if (event.getEntity() instanceof TableTestEntity) { // 执行你的业务逻辑 tableTestRepo.doSomething(); } } }
这种方式下,监听器由Spring完全管理,依赖注入可以正常工作,无需额外处理。
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

