You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中CRUDRepository注入工具类后调用时为空问题求助

问题根源分析与解决方案

兄弟,我一眼就看到问题所在了——**你在ActionTrackerInterceptor里手动new MyActionLogUtil()了!**这是Spring依赖注入里最典型的错误之一。

核心问题

Spring的依赖注入只对它自己容器中管理的Bean生效。你给MyActionLogUtilImpl加了@Component,Spring确实会创建一个实例并正确注入actionLogRepository,但你在拦截器里手动new出来的那个MyActionLogUtil实例,完全是脱离Spring管控的“野生对象”,Spring根本没机会给它注入任何依赖,所以actionLogRepository自然就是null。

另外,你的ActionTrackerInterceptor作为Hibernate拦截器,如果不是Spring管理的Bean,也没法直接注入其他组件,这也是需要解决的点。


解决方案(推荐优雅版)

让拦截器成为Spring管理的Bean,并通过构造注入获取MyActionLogUtil:

  1. 改造拦截器,让它被Spring管理
    给ActionTrackerInterceptor加上@Component注解,并用构造注入获取工具类实例:

    @Component
    public class ActionTrackerInterceptor extends EmptyInterceptor {
    
        private final MyActionLogUtil actionLogUtil;
    
        // 构造注入(Spring推荐的注入方式,避免空指针风险)
        public ActionTrackerInterceptor(MyActionLogUtil actionLogUtil) {
            this.actionLogUtil = actionLogUtil;
        }
    
        @Override
        public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
            Action act = (Action) entity;
            ActionLog actionLog = new ActionLog(...some data inserted...);
            // 直接用Spring注入的工具类,不要再new!
            actionLogUtil.logIt("DELETED", actionLog);
            System.out.println("Record " + entity + " is deleted.");
        }
    }
    
  2. 配置Hibernate使用这个Spring管理的拦截器
    在application.properties或application.yml中添加配置,告诉Hibernate用Spring容器里的拦截器:

    spring.jpa.properties.hibernate.ejb.interceptor=com.yourpackage.ActionTrackerInterceptor
    

    (把com.yourpackage替换成你拦截器所在的实际包路径)


备选方案(如果拦截器无法被Spring直接管理)

如果因为某些限制,拦截器必须手动创建,可以通过Spring上下文获取容器中的Bean:

  1. 创建Spring上下文持有类

    @Component
    public class SpringContextHolder implements ApplicationContextAware {
        private static ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext context) throws BeansException {
            applicationContext = context;
        }
    
        public static <T> T getBean(Class<T> beanClass) {
            return applicationContext.getBean(beanClass);
        }
    }
    
  2. 在拦截器中获取工具类实例

    public class ActionTrackerInterceptor extends EmptyInterceptor {
        @Override
        public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
            Action act = (Action) entity;
            ActionLog actionLog = new ActionLog(...some data inserted...);
            // 从Spring上下文获取Bean,而不是new
            MyActionLogUtil util = SpringContextHolder.getBean(MyActionLogUtil.class);
            util.logIt("DELETED", actionLog);
            System.out.println("Record " + entity + " is deleted.");
        }
    }
    

    这种方式不如第一种优雅,仅作为特殊场景的备选。


额外注意事项

  • 你的工具类接口名字有拼写错误:ActionyLogUtil应该是ActionLogUtil吧?修正拼写避免不必要的错误。
  • 在logIt方法中,你注释掉了actionLog = new ActionLog(...),实际运行时要确保actionLog不为null,否则调用save会抛出空指针异常。
  • 事务方面:deleteActionRecord方法的@Transactional会覆盖拦截器中的操作,logIt里的save会继承当前事务。如果需要日志操作独立于删除事务,可以给logIt方法加上@Transactional(propagation = Propagation.REQUIRES_NEW)。

内容的提问来源于stack exchange,提问作者Matexon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:08:03