我们知道getStatus这个方法是在servlet-api的3.1.0版本之后才有的,既然报了这个错误,说明肯定是引用到了老包(已经找到了类,但是这个类没有这个方法)。
你说没有啊,我明明在pom.xml里面声明的是3.1.0啊,也没有声明更老的版本的依赖了,而且mvn本地仓库中也有这个jar包啊。
真正的问题不在于这,你虽然没有声明显示依赖,但是你显示声明的依赖可能隐含依赖老版本的jar包(即你要明确依赖xxx,但是xxx的jar包里面的pom又依赖yyy,你只有解压缩xxx的jar包,并查看pom才能知道隐含依赖),而如果这个依赖在pom.xml中排在新版本的前面(这里要特别注意一下,mvn是按照声明的依赖顺序依赖的,前面有这个类,就不在继续找后面的),那么mvn编译时就找到了加载在前面的这个jar包,实际上代码里面我们先import的这个类,于是mvn编译时也会找这个类,先找到就不再继续找了,你后面再显示声明新版本的依赖也是没用的,除非是一个新类。
你可以使用mvn dependency:tree这个命令分析一下,哪里引用到了老包,要看整个依赖树才能看的出来(因为要跳过一层显示依赖,看显示依赖的隐含依赖,或者看显示依赖的隐含依赖的隐含依赖,以此类推,直到找到你的老版本jar的引入)!!
简单说一下我们的具体问题,我们的问题的根因定位出来我都诧异了。
我们的一个子项目依赖xxx-channel和servlet-api-3.1.0(注意声明的依赖顺序,先声明的xxx-channel,后声明的servlet-api-3.1.0,注意mvn是按照声明的依赖顺序加载的),而是xxx-channel依赖于公司自研的一个xxxfrm-1.6.4,而问题是这个xxxfrm-1.6.4隐含依赖servlet-api-3.0.alpha.1, 导致编译时先加载了xxx-channel,也就等同于先加载了servlet-api-3.0.alpha.1,导致编译时先加载了老版本的jar,导致getStatus方法找不到,导致编译失败。
那为啥以前的库没有这个问题呢??
原因就在于公司自研的这个xxxfrm-1.6.4在以前的私有mvn中央仓库中依赖的的就是servlet-api-3.1.0,而新的私有mvn中央仓库中自研的这个xxxfrm-1.6.4中声明的依赖是servlet-api-3.0.alpha.1。
哈哈,xxxfrm的版本都是1.6.4,但是这里面依赖的servlet-api的版本却不同,看起来有点坑爹。。。
而,如果我们本地仓库有这个xxxfrm-1.6.4(以前的私有mvn中央仓库下载下来的),即使换了新的mvn私有库,也不会再重新拉取,这个时候编译不会报错,因为servlet-api都是3.1.0嘛。如果没有,则会重新拉取,这个时候就会有问题了!!
也就是我们自己用的不管是win还是linux都没有问题,只要换了一个新的环境或者把本地仓库删了重新拉取,就会有问题,原因就在这里了。
解决办法很简单,就是把新版本的依赖提前,即将servlet-api-3.1.0的依赖声明提到xxx-channel依赖声明之前。
哈哈,软件界有一句不成文的名言,那就是只要能复现的问题,就不是问题(可能困扰一时,但最终肯定会水落石出的。)
尽管刚遇到的时候感觉“诡异”,那是因为我们还没有找到问题的本质,问题的根因。
只要我们一步一步地去探索,去追寻,明确的问题肯定会有明确的答案和解释!!
注:
1、网上很多都是tomcat版本低或者spring版本的问题,实际上都是依赖问题,理解依赖的本质也就容易找到问题的根因了,至于网上大部分说的从什么版本换到什么版本,针对自己的问题还得好好斟酌一下;
2、这里涉及到自研的库,如果不涉及,后面使用spring boot应该不用操版本兼容的心了。
网友评论