背景
本故事采自真实事件改编,如有雷同,纯属巧合。背景是这样的,在一次正常需求开发过程中,我们系统提供的接口服务 Request入参对象新增一个枚举。上线后确出现了问题。
【问题描述】
接口服务上线后,调用方传过来的枚举调用接口解析报错 提示解析不到这个字段属性。
FieldName:[methodFields] cannot be resolved.
对方接口可用率瞬间变低,紧急回滚后,恢复正常。
【事故级别】
- P0
原因排查:
思路一:
出现这种情况,我们首先是怀疑自己作为接口提供方,是不是打包出了问题,于是乎,我们从服务器上down下来打好的snapshot包,用反编译软件解析后发现,新增的字段存在。既然存在,为什么解析不了呢?
思路二:
接着我们怀疑是不是机器出现了问题,于是新扩容了几台,部署上代码后发现,问题依然是存在,新增的字段确实打包文件里有,但是通过接口服务调用就是解析不到。到此时,所有思路都中断了,时态陷入僵局。
思路三:
这个时候有人提出,是不是我们这个枚举类有问题,于是我们用其他接口中的入参试了一下,新增字段后打包发布,发现确实没问题。这种情况之前没遇到过,所以一时间也不知道如何处理。
思路四:
现在问题范围已经缩小聚焦到这个对象上,于是我们开始对这个类记性排查。果然发现了一些端倪!
原因分析:
我们修改的这个枚举类,在另外一个项目里也存在一个相同路径、相同名称的类。
于是我们尝试是否是因为这个相同类导致的问题,我们去服务代码里,去掉这个依赖,然后打包上线。发现一切正常了...
继续深入排查,这个相同类所在的另外一个maven服务中,很多相同的路径类存在,经过了解后才知道,当时有人为了创建项目图方便,直接copy了我们这个服务的层级接口,甚至路径都没有修改。才导致出现两个相同路径的对象存在。
那么,为什么?相同路径,相同名称,类加载器为什么加载了另外一个项目里的类?不加载我们项目里的呢?
抱着这个疑问,我们来用demo复现一下事情的所有经过。
步骤1:我们先创建两个同路径的项目 TestDemo1、TestDemo2
步骤2:我们在另外一个项目里引用TestDemo2的jar包
运行后结果:
步骤3:我们在这个项目里继续引用TestDemo1的jar包,并且运行后发现 依然是TestDemo2的结果
如果我们把maven包依赖的顺序调整一下呢?先引入TestDemo1,再引TestDemo2,结果发现
所以,相同路径,相同名称的两个jar包类引入的顺序先后,决定了先加载谁,而后面的不加载谁。
总结
- 我们在日常开发过程中,如果发现加的字段,没有被解析加载到,一定注意看下是否存在相同路径、相同名称的类。
- 如果是自身服务的包依赖,在pom中尽量往前放,依赖的第三方包往后放。
- 如果说必须兼容的话,必须优先指定加载某个jar下的类可以自己重写一下类加载器,可以参考 blog.csdn.net/weixin_4206…