一次java.lang.NullPointerException的排查之旅
- 问题由来
- 问题分析
- 问题处理
问题由来
最近在项目中遇到了一个比较奇怪的java.lang.NullPointerException,就是说在自己的本地环境中,功能正常,运行无异常。但是测试环境点击同样的功能时却总是对应的字段查不到数据,但是数据库中这个字段又是有数据的,测试环境的效果就像这样
那么这个问题究竟是怎么产生的呢?
问题分析
既然测试环境不好使,那么首先回到本地环境看一下这个功能是否正常,启动本地项目后,点击对应功能的功能页面看到效果
说明自己本地功能时没有问题的,那么测试环境为什么对应字段有数据但是却一直查不出数据呢?查看测试环境服务器的日志打印,整体上的日志并没有什么异常之处,但是仔细查看日志会找到有一段异常信息
序列化出错java.lang.NullPointerException
那么回到对应的controller OrderClueRuleController.java 查看对应156行内容
为了更好的打印错误日志,在本地项目中这里将异常信息通过 e.printStackTrace(); 打印出来。本地项目执行之后的日志如图
并没有异常信息,到这里怀疑是否是本地代码与测试环境代码不一致导致的。于是重新更新了本地代码,终于复现了问题,本地打印了异常信息代码行数
我们在对应的OrderClueRuleController.java:149 打上debug再次查看具体问题
入参是没有问题的,入参有值,这是注意到了一点
在service sysService后面跟了一个NullPointerException,选中sysService bean查看为 null
到这里问题基本也就明了了,下面开始处理问题。
问题处理
基于上面的问题分析,基本也定位到了问题所在,sysService bean为null,那么sysService为什么会为空呢?查看更新的代码就找到了问题,sysService 的 @Autowired 注解丢失了。@Autowired 注解的作用是如果在一个类中声明了 @Autowired 注解,那么 Spring 容器会自动帮助我们创建一个 Bean 并注入到该类中,现在其实 sysService bean是没有注入到 controller OrderClueRuleController 中的,因此就有了这个问题。最后其实发现这个@Autowired 注解本来是有的,只是在代码合并的时候处理冲突导致丢失了。
最后,其实这样的问题并不难排查,只是往往不太会往这个方向想,并且代码编译、启动都没有报错。通常情况下遇到这样的java.lang.NullPointerException 异常都会想到入参是否未传,而不太会去注意入参的调用 bean是否为 null。
这里补充一下 @Autowired 和 @Resource 注解在注入类时的小区别:
@Autowired:用于对Bean的属性变量、属性的setter方法及构造方法进行标注,配合对应的注解处理器完成Bean的自动配置工作。默认按照Bean的类型进行装配。
@Resource:与@Autowired作用相同, 区别在于:@Aautowired默认按照Bean类型装配,而@Resource默认按照Bean的实例名称进行装配。