记录一次LinkError排错:
发现:通常有两个环境,一个日常,一个灰度。于是,日常测试好了,上灰度了,可怕的问题来了,访问某一功能,就报类linkerror错误了
过程:
根据以往的经验,这种错误必定是类冲突了,那么类冲突一般通过排除类的加载去解决,但是我们这种情却不是这样,有一个中间件团队的插件(pandoda),另外应用里面一般也会有中间件相关的包,为了统一的管理,pandoda容器会对中间件相关的插件用自己的classloader加载,实现就是重写webappClassloader先从自己的export库中找到,找不到就走webappClassLoader的逻辑。
为了弄清类的加载关系,我们在java启动参数中加了-verbose:class(还有常用verbose:gc(参见相关这个配置的文档)),然后在日常和灰度环境中grep statLogger jboss_out.log中出现上图的日志,而在日常没有。显然,这就很奇怪了,为什么灰度会加载两次,一次是pandora插件的加载(这个是正常的加载),一个是webAppClassLoader的加载,究竟谁触发的呢?
还有为什么日常和线上加载会不一样呢?那么很容易想到,环境配置不一样,通过比较,确实不一样,于是我们把中间件等基本的配置加上,但是重启后没有任何影响。
随着问题的深入,grep eagle eye * -G1 查看加载这些类的前后触发的类,发现有一个uc。****的.jar包引起的,然后再检查环境,日常没有,加上,于是在日常环境重现了。
本来从中间件的classloader加载是正确的,为什么应用的classloader又去再加了?找到也没有找到原因,只有启动debug,debug的应用启动的WebAppClassLoader ,在触发时发现调用了DOOM.trace()方法提前触发了类的加载,由于当前在WebAppClassLoader下,中间件的类classloader并没有完全加载完成,由于WebAppClassLoader先查找中间classLoader的导出类,然后再去找
验证:遇到环境问题是,首先保证环境配置一致,第二个,debug出现问题的地方,详细看堆栈调用信息可以发现问题