发现bug:
在服务器上部署后台服务并验证能够正常运行,但是一次修改配置重启后突然出现了一个空指针bug,部署的程序并没有改变
2. 定位bug:
空指针定位到一个变量,查找代码发现变量初始化来自于读取配置文件,但是检查配置文件中有正常配置相应值,所以无法找到原因。
后来在开发机器上调试服务都没有问题,只好重新部署服务到服务器,发现是能够正常运行。
比较两次部署的服务包,内容完全一致,唯独配置文件的二进制不同,使用十六进制查看配置文件,发现文件开头多出了3个字节的BOM头。
3. 解决bug:
使用文本编辑工具将配置文件的BOM头去掉后,重新启动服务,验证能够正常运行。
4. 分析bug:
- Bug产生的原因:Windows系统对Unicode编码的文本文件会使用BOM头来定义编码方式和字节序,如果使用记事本编辑Unicode文件保存后就会默认添加BOM头。而Java的原生IO并不会处理BOM头,会将BOM头视为普通内容,JDK Bug中有此记录,详见JDK Bug 4508058,结论是该Bug不会修复,为了更好的适应性。
- Bug的避免:
- 建议不使用Unicode编码的配置文件,有些IDE默认都是ISO8859-1,这样兼容性最好。
- 在Windows系统上编辑文本文件需要使用编辑工具,不要默认使用记事本,编辑要注意BOM头问题。
- 为使程序兼容性更好,读取文件时程序应识别并去掉BOM头。已提供读取配置文件工具,源码详见UnicodeInputStream。
- 下载resource-utils库或者可以引入maven依赖库
<groupId>net.sunyijun</groupId>
<artifactId>resource-utils</artifactId>
使用该工具库读取配置可以兼容BOM头。具体用法详见README。
附BOM头规则:
00 00 FE FF = UTF-32, big-endian
FF FE 00 00 = UTF-32, little-endian
EF BB BF = UTF-8,
FE FF = UTF-16, big-endian
FF FE = UTF-16, little-endian