同名类冲突-CASE1.两个第三方JAR包中包含同名类
1. 问题描述
项目使用的相关技术栈:Alitomcat+Pandora
日常环境下邮件发送正常,进入预发环境中邮件发送失败。抛出异常(偶现)
java.net.SocketException: Connection reset
javax.mail.MessagingException: Can\’t send command to SMTP host;nested exception is:
java.net.SocketException: Connection closed by remote host
javamail SSL peer shut down incorrectly
2. 排查思路
2.1 邮箱发送源码有BUG
大概网上查了下,该异常的导致原因。没有发现啥问题。朝着邮件发送源码有BUG的方向排查了好久@-@
2.2 环境相关的问题,先看看邮箱相关的JAR包
发现邮箱相关的JAR包有好多个,如下图。再看看抛出异常的类javax.mail.Transport, 同时处在在多个JAR包中。javax.mail\javax.mail-api\mail
2.3 同名类有多个,两个不同环境,分别从哪个JAR包加载?
对比日常环境、预发环境加载的javax.mail.Transport,发现两个环境加载的包不一样。
分析到这里存在以下疑问:
- 如果项目中出现多个全限定名相同的类,从哪个JAR包中加载?顺序是怎么样的?
- 目前项目是Docker化部署的,为啥日常环境、预发环境部署出现不一样? Docker化部署有覆盖不到的场景?
2.4 同名类从哪个JAR包中加载?顺序是怎么样的?
参照StackOverFlow上的一个问答,从/lib目录下,加载JAR包的顺序是什么。某个Tomcat版本巧合之下,加载JAR包是按字母序来的。实际官方指出开发Web应用时,不应该依赖于对JAR包的加载顺序,它的排序取决于底层操作系统搜索排序,即 find “/path,” -name *.jar,find命令返回的顺序是随机的,跟磁盘上文件内容有关系。
用提供的静态 class 查找工具findclass.py,在WEB-INF/lib 目录下,查找对应类的JAR包。日常\预发环境找到的包顺序相反。
2.5 Docker化部署前提下,为什么会出现部署不一致情况?
环境是一致的,但是实际应用时,还是可能会有细节上的不同。
3. 总结
- 不要引入非必要的JAR包,明确功能,然后引入
- 可以认为加载的类时,选用该类所在的JAR是无序的(取决于find命令返回顺序)。官方指出不应对JAR包加载顺序有依赖。
- Docker化部署理论上是环境一致的,但实际应用时,可能还是会存在细节上有不一样,比如find命令返回顺序不同。
参考链接:
https://bz.apache.org/bugzilla/show_bug.cgi?id=57129