记一次maven jar包冲突的排查和解决过程,干货分享

2021-08-31 15:35:56 浏览数 (1)

一、背景

项目新拉了一个分支开发,前几天好好的,加了一些功能后发现部署一直失败。

总是报同一个错误(详见2.1),而且并不像是自己代码的错误。

和同事花费了一些时间进行排查,最终定位并解决问题,记下分析思路。

二、排查步骤

注:截图均来自自己的本地练习项目,而不是排查一模一样的截图,只是演示效果。

2.1报错内容

代码语言:javascript复制
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[]]
        at java.util.concurrent.FutureTask.report(FutureTask.java:122)
        at java.util.concurrent.FutureTask.get(FutureTask.java:192)
        at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:941)
        at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:872)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1421)
        at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1411)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[]]
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167)
        ... 6 common frames omitted
Caused by: org.apache.catalina.LifecycleException: Failed to start component [Pipeline[StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[]]]
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5166)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        ... 6 common frames omitted
Caused by: org.apache.catalina.LifecycleException: Failed to start component [org.apache.catalina.authenticator.NonLoginAuthenticator[]]
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167)
        at org.apache.catalina.core.StandardPipeline.startInternal(StandardPipeline.java:182)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        ... 8 common frames omitted
Caused by: java.lang.NoSuchMethodError: javax.servlet.ServletContext.getVirtualServerName()Ljava/lang/String;
        at org.apache.catalina.authenticator.AuthenticatorBase.startInternal(AuthenticatorBase.java:1186)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        ... 10 common frames omitted



2019-05-28 11:30:28.605  WARN 25 --- [main]  ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
2019-05-28 11:30:28.640 ERROR 25 --- [main]  o.s.boot.SpringApplication               : Application startup failed
org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:137)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)

2.2 尝试

第一反应是给出的错误信息非常不明确,就是说tomcat启动失败。

(1) 由于这个项目是一个maven项目,直接用maven编译命令查看是否可以编译成功,发现都SUCCESS.

(2) 尝试把代码发布到不同的环境,查看是否是环境造成的,发布到了其他环境上,偶尔能成功,发布master都成功,排除了环境bug。

(3) 在google上搜报错信息,大多数提示是servlet-api的jar包冲突。

然后使用mvn dependency:tree 查看依赖树,发现新引入的几个jar包其中有一部分确实包含了servlet-api。

然修改pom.xml文件,排除servelt-api相关依赖。

发现依旧报错。

(4) 由于新增了多个jar包不确定是哪个jar包引起的,因此基于这个分支新拉出一个分支用于删除依赖排错。

删除最可以的新的jar包以及相关的本地代码,重新部署,发布成功。

然后定位到此jar包的servlet-api是通过jboss的包引入的。

由于这是第二方的dubbo的调用api jar包,因此可以放心去掉jboss。

直接排除了jboss的依赖。

三、总结

3.1 擅于使用IDEA插件

项目右侧的maven选项卡里 有”show dependencies“

可以查看依赖,可以搜索,可以放大等

可以查看冲突,保存UML等

另外还可以安装 Maven Helper插件

方便的搜索并排除依赖。

安装后pom.xml文件会多一个”依赖分析“选项卡

切换过去会显示冲突的jar包,也可以切换到All Dependencies 列表或者树,也可以在上搜索自己想看的jar包。

查看依赖,查看冲突,并可以方便的通过右键”exclude“自动在pom.xml文件中的该依赖里排除该jar包。

3.2 要积累并实践排错方法

3.2.1 细心

要细心,刚开始以为提示信息不多,其实并没有注意到

Caused by: java.lang.NoSuchMethodError: javax.servlet.ServletContext.getVirtualServerName()Ljava/lang/String;

这行关键的错误,很明显极有可能是servlet的jar冲突。

3.2.2 要积累和实践

上面是总结的排查问题的方法,在这次排查中就用到了几个关键的部分。

1 code review 和master比代码,分析新增的依赖

2 日志

3 命令

(1)mvn命令,包括查看依赖树,编译查看是否通过等

(2)git命令,拉取新分支排查问题,避免之前的分支代码错乱污染、误删等

3 换环境

4 搜索引擎

5 控制变量法

3.2.3 知其所以然

(1)为啥dubbo的接口包会引入Jboss呢?

猜测其参数或者返回值里有jboss相关的类,进源码搜索,发现果然如此。

(2)为啥排错就行了呢?冲突怎么自动决定用哪个jar呢?

要顺便了解一下maven的依赖传递机制,参见https://www.cnblogs.com/ygj0930/p/6628429.html

 1:如果依赖路径的长度不同,则“短路优先”:

         A—>B—>C—>D—>E—>X(version 0.0.1)

         A—>F—>X(version 0.0.2)

         则A依赖于X(version 0.0.2)。

     2:依赖路径长度相同情况下,则“先声明优先”:

         A—>E—>X(version 0.0.1)

         A—>F—>X(version 0.0.2)

         则在项目A的中,E、F哪个在先则A依赖哪条路径的X。

如果想排查传递依赖,以用 标签。

四、总结

快速定位和解决问题是一种能力,需要积累和实践。

很多人遇到问题,尤其是新手,不是先思考,而是先百度,先问别人。

更可怕的是,没有这种积累方法的意识,目光短浅,只着眼于解决眼前的问题,剩下的”以后再说“。

总是有很大碰运气的成分,也容易浪费很多时间,自己也无法提高排错的能力。

网上有为了解决这个问题mvn装了好几次,搞了一两天都不行的,其实就是没有思考到问题的核心。

希望大家可以积累排错能力,而不是毫无头绪地,不断试错。

另外我们经常使用idea却可能并没有安装高效的插件,并不熟悉其高效的快捷键。

我们经常使用Maven,但是并没有系统掌握mvn所有原理和用法。

我们经常使用spring/mybatis却很少有人系统看过期官方文档,更别说读懂源码。

我们经常。。。

我们加入了很多技术群,真正分享技术、真正帮助解决问题的的人很少。

真正有人分享干货自己却未必感兴趣,未必去下载去看,总是遇到问题了才想到着急。

其实排错,看似是技巧,其实和基础和经验无不相关,我们工作的同时要多思考为什么,积极学习核心技术的的源码。

本文也分享了自己总结的排查思路,大家如果有其他好的思路也欢迎补充,共同进步。

五、其他

之前写过一篇排错的方法总结《代码排错和避免错误的正确姿势》感兴趣可以参考一下

https://cloud.tencent.com/developer/article/1868978

如果觉得本文对你有帮助,欢迎点赞,欢迎关注我,如果有补充欢迎评论交流,我将努力创作更多更好的文章。 另外欢迎加入我的知识星球,知识星球ID:15165241 一起交流学习。 https://t.zsxq.com/Z3bAiea  申请时标注来自CSDN。

0 人点赞