@Autowired注入PushDataTraceLogService时出现NullPointerException问题
异常类中@Autowired注入服务空指针问题解决
问题描述
我定义了一个继承RuntimeException的异常类PushDataException,添加了@Component注解并通过@Autowired注入PushDataTraceLogService,但使用该服务时出现空指针异常。已知pushDataTraceLog实例不为空,但pushDataTraceLogService始终为null。
相关代码
异常类代码
@Component public class PushDataException extends RuntimeException { @Autowired private PushDataTraceLogService pushDataTraceLogService; }
PushDataTraceLogService接口
public interface PushDataTraceLogService { void save(PushDataTraceLog pushDataTraceLog); }
实现类代码
@Service public class PushDataTraceLogServiceImpl implements PushDataTraceLogService { @Autowired private PushDataTraceLogRepository pushDataTraceLogRepository; @Override public void save(PushDataTraceLog pushDataTraceLog) { pushDataTraceLogRepository.save(pushDataTraceLog); PushDataTraceLog.destroy(); } }
堆栈跟踪信息
java.lang.NullPointerException: null at com.publicissapient.kpidashboard.apis.pushdata.util.PushDataException.setTraceLog(PushDataException.java:60) at com.publicissapient.kpidashboard.apis.pushdata.util.PushDataException.<init>(PushDataException.java:52) at com.publicissapient.kpidashboard.apis.pushdata.service.impl.AuthExposeAPIServiceImpl.validateToken(AuthExposeAPIServiceImpl.java:127) at com.publicissapient.kpidashboard.apis.pushdata.controller.PushDataController.savePushDataBuilds(PushDataController.java:67) at com.publicissapient.kpidashboard.apis.pushdata.controller.PushDataController$$FastClassBySpringCGLIB$$61a69129.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:123) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) at com.publicissapient.kpidashboard.apis.pushdata.controller.PushDataController$$EnhancerBySpringCGLIB$$a6ea830e.savePushDataBuilds(<generated>) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1070) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
原因分析
- 异常类未被Spring容器管理:虽然加了
@Component,但异常通常是通过new PushDataException()手动实例化的,这种方式创建的对象不在Spring管控范围内,Spring不会自动注入@Autowired字段。 - RuntimeException实例化机制限制:继承自
RuntimeException的类,实例化时不经过Spring的Bean创建流程,导致依赖注入失效。
解决方案
方案一:构造函数传入服务
不在异常类中依赖注入,而是在抛出异常时将服务作为参数传入:
public class PushDataException extends RuntimeException { private final PushDataTraceLogService pushDataTraceLogService; // 构造函数接收服务实例 public PushDataException(String message, PushDataTraceLogService service) { super(message); this.pushDataTraceLogService = service; setTraceLog(); } private void setTraceLog() { PushDataTraceLog log = new PushDataTraceLog(); // 设置日志属性 pushDataTraceLogService.save(log); } }
抛出异常时,从Spring管理的Bean中获取服务传入:
// 在Spring管理的Service类中 @Autowired private PushDataTraceLogService pushDataTraceLogService; // 抛出异常的逻辑 throw new PushDataException("Token验证失败", pushDataTraceLogService);
方案二:重构代码,日志逻辑移出异常类
将保存日志的逻辑从异常类中剥离,在抛出异常前完成日志操作:
// 在Service类中 @Autowired private PushDataTraceLogService pushDataTraceLogService; public void validateToken() { if (token无效) { // 先保存日志 PushDataTraceLog log = new PushDataTraceLog(); // 设置日志信息 pushDataTraceLogService.save(log); // 再抛出异常 throw new PushDataException("Token验证失败"); } }
这种方式让异常类只负责传递异常信息,符合单一职责原则,是最推荐的做法。
方案三:通过ApplicationContext手动获取Bean(不推荐)
如果必须在异常类中使用服务,可以通过ApplicationContext手动获取:
@Component public class PushDataException extends RuntimeException { private static ApplicationContext applicationContext; @Autowired public void setApplicationContext(ApplicationContext context) { applicationContext = context; } private void setTraceLog() { PushDataTraceLogService service = applicationContext.getBean(PushDataTraceLogService.class); PushDataTraceLog log = new PushDataTraceLog(); service.save(log); } }
注意:这种方式会增加代码耦合度,且需要确保ApplicationContext已完成初始化。
内容的提问来源于stack exchange,提问作者shivani chittauri
相关产品推荐
相关产品推荐

