惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 三国梦回

spring boot 项目中oracle datasource设置schema spring cloud项目中,在bootstrap.yml中指定了active的profile,结果不生效 线上服务重启后,从nacos取不到配置了,怎么回事 nginx location没学好,把自己坑了一把 技术问题记录20260125 最近遇到的两个技术问题记录 linux服务器文件上传失败 线上遇到的redis和数据库数据未同步问题、redisson内部实现问题 复杂业务系统线上问题排查过程 nacos中配了一个数字,springboot取回来怎么变了 简单记录下最近2个月完成的线上系统迁移工作 centos停服,迁移centos7.3系统到新搭建的openEuler 端口telnet不通排查过程 https证书中的subject alternative name字段作用及如何生成含该字段的证书 linux中如何判断一个rpm是手动安装还是通过yum安装的 对接服务升级后仅支持tls1.2,jdk1.7默认使用tls1.0,导致调用失败 网络抓包文件太大,如何切分 分页查询不加排序有问题,加了排序怎么还有问题 利用mybatis拦截器记录sql,辅助我们建立索引(二) 利用mybatis拦截器记录sql,辅助我们建立索引(一) sql server版本太老,java客户端连接失败问题定位
一个java空指针异常的解决过程
三国梦回 · 2025-07-18 · via 博客园 - 三国梦回

背景

上一篇讲了我们从另外一个部门迁移了一个线上系统回来,迁回来是为啥呢,因为这个好几年没新需求的系统,突然有新需求要开发,然后我就开发呗,其实就是在某个服务里加点表,然后提供个查询接口给app。这个服务用的架构是厂商的,不是servlet容器那一套,它技术还是很厉害,其实是c语言写了个reactor这种类似netty的通信框架,通信协议是私有的tcp协议,然后启动时还通过jni拉起了一个java虚拟机,通信框架就负责底层通信,并且像servlet那样来调用上层的java类中的service方法这样。

至于为啥厂商这么玩,我觉得无非是把底层这套通信框架打成二进制提供给我们,提高技术壁垒,防破解啥的,并且通过私有协议提升维护难度,这样的话,就可以一直收我们维护费了。这些就不过多吐槽了,反正好多服务就是这样被厂商绑死了。

在windows上,这个进程没法像tomcat这类容器一样运行起来,每次只能对java代码部分进行junit单元测试,只能在linux上才能运行起来。

像java代码部分,我们自己是用了spring那一套,就像下面这样,启动时直接new一个spring的ClassPathXmlApplicationContext,而下面的location就是application.xml这种spring配置文件的url。

image-20250718195927048

由于厂商也提供了些自己的访问数据库的框架,之前这个服务就是用的厂商这套(类似于jdbcTemplate操作sql语句);我接手这个服务之后,感觉不太喜欢厂商那套,就还是引入mybatis的mapper这套,如下:

image-20250718200332238

结果,我本地junit调试时好好的,丢到服务器上,直接运行不起来了。给我报了个空指针。

image-20250718200435739

解决过程

各种怀疑

上面的图里,看着是mybatis在创建一个什么XPathFactory的时候报错了,然后上图又说解析什么mapper.xml失败了,我还在想,是文件路径没对吗,结果文件路径挺对的:

image-20250718200726559

接下来,开始怀疑起了mybatis,由于接手的这个项目,素质不怎么样,各种jar包冲突啥的,大家看我下图就知道了,就上面报错的堆栈里的org.apache.ibatis.parsing.XPathParser这个类,我在项目里一搜,发现同名类有两个,为啥呢,因为下面第一个jar包是厂商的,它把mybatis的源码封进了自己的jar包里,且没改包名:

image-20250718201045508

当然了,厂商那个jar包里不止这一个,拷贝了很多类进来,也不知道拷贝进来后改了些啥。

我这时候的想法是,看看到底加载的哪个class吧。

查看类加载情况

然后在jvm的启动参数加了打印类加载的jvm参数: -verbose:class

image-20250718201521400

注意,这个是打印到console,或者对console进行重定向到文件。

我这边看了下,发现是对的,仔细检查了,没发现加载了厂商的jar包的类,看起来是对的:

image-20250718201817975

看堆栈相关代码

然后开始在本地junit调试,结果没走到报错的地方。

看之前那个错误堆栈,报错就是在下面的jdk1.7中的XPathFactoryFinder类的220这一行:

image-20250718202429610

然后,这个resource应该就是触发空指针的,如果说resource为null,那么217行这个迭代器就有问题,通过迭代器的next获取出来的值为null;而迭代器是在215行的createServiceFileIterator赋值的。

image-20250718202651289

点进来后就傻了,有分支,不知道走了哪一条,好在天无绝人之路,此时,之前的-verbose:class参数起了作用:

image-20250718202854173

通过这里分析,在加载完XPathFactoryFinder类后,不久就加载了javax.xml.xpath.XPathFactoryFinder.SingleIterator,那意思就是走了if那个分支。

但目前对怎么解决这个问题还是不清楚,无奈,先本地debug。

debug

虽然本地junit不能完全模拟linux服务器上的状况,但是先试试吧,结果,本地调试发现:

在之前那个分支处,本地windows时,classloader不是null:

image-20250718204203502

那我是否怀疑了classloader的问题呢,怀疑的不多,因为以前本地调试tomcat的时候已经遇到过,本地debug时用的classloader和最终把war包丢到tomcat里运行时用的classloader那些,确实不一样。

在debug的过程中,对这个类的理解加深了一些,看起来,这个XPathFactoryFinder主要就是要获取到一个XPathFactory。

image-20250718205146883

先是从property中查找,property为javax.xml.xpath.XPathFactory:http://java.sun.com/jaxp/xpath/dom,如果能找到对应的实现类,就用这个实现类去创建对应的XPathFactory,这块就和java中的SPI机制类似:

image-20250718205308523

接下来呢,会尝试从配置文件获取C:\Program Files\Java\jdk1.7.0_80\jre\lib\jaxp.properties

image-20250718205450964

如果还是没有,才会走到我们报错的地方,即用spi机制,问题是我们因为classloader为null,走不到下图这里:

image-20250718205714631

开启debug日志

在debug过程中,发现很多debug日志:

image-20250718205841912

这个日志如何开启呢?

image-20250718205905800

我们设置了下,如下:image-20250718210000551

image-20250718210125387

这下,通过日志,我们更加明确了程序运行的轨迹。

设置property解决bug

接下来,就是怎么解决了,在debug过程中,我们发现,本地windows的话,默认最终的实现类就是com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl,其实就是jdk自带的:

image-20250718210259269

image-20250718210334610

那我们这里也就好说了,设置下property吧,解决问题就行了,至于为啥classloader为null,就没有继续深究了:

image-20250718210526808

这次就运行正常了:

image-20250718210627103

总结

bug记录下还是挺好,因为很快就忘了,后来要写上线变更文档,才想起来这么个事。