笔者在解决业务问题的时候,很多业务提出了为啥我的服务在测试环境啥问题都没有,发布生产就出问题了,第一反应是配置不一样?实际上部分原因可能还与发布的容器有关,比如Tomcat8,比如jar冲突。刚好解决了jar冲突的事情,总结分析原因。
Tomcat的新版本是可以直接下载源码的,但是Tomcat7就只能
Index of /dist/tomcat (apache.org)
记得下载src
以非嵌入式tomcat 7 8 为例
tomcat加载WEB-INF/lib是在org.apache.catalina.loader.WebappLoader加载的
可以看到加载是通过
DirContext
实现的,这个在tomcat有2种方式WAR、File
Tomcat通过解压运行,加载默认通过File,会把lib下得jar按照字母排序,加载jar的顺序固定,所有环境一样,要么都冲突,要么都正常,环境验证好就不存在类冲突问题。
tomcat8的设计有些不同,代码重构了,在org.apache.catalina.loader.WebappClassLoaderBase下的start
可以看到
进一步继续,直接file.list获取过滤jar,并没有排序
以macOS为例
直接查看jdk源码
初步看扫描的代码,大致是顺序与服务器的信息有关,导致Tomcat8在不同服务器WEB-INF/lib的jar的顺序不一样,加载的类如果有冲突会不一样。
实际上Tomcat7是不存在问题的,Tomcat8就会出现类冲突的情况,本质还是Tomcat8暴露了类冲突的情况,并不是Tomcat7解决问题,而是隐藏了问题。
解决类冲突还是需要静态扫描,人工比对处理(排jar),扫描也很好写,包与类路径一样即为可能冲突类
spring boot又是怎么处理的呢,通过jarFile的迭代器迭代的,所以是顺序的,并且jar启动的的jar的BOOT-INF/lib也是不会顺序变换的
仅仅是Tomcat使用读取文件的方式启动就会根不同机器的环境相关,顺序不一致而出现类冲突的暴露问题,说明了不同环境问题出现的原因也会跟执行容器相关。这可能也是spring boot发展的一个原因。当然Tomcat也可以war读取,不解压运行,就不会有这个问题了,只是不知道什么原因不常用。