乐趣区

关于java:JAR冲突问题的解决以及运行状态下如何查看加载的类

明天碰到群里小伙伴问,线上程序如同有多个不同版本的 Netty 包,怎么去看到底加载了哪一个?

在说如何看之前,先来说说,当你开始意识到我的项目里有多个不同版本的 Jar 包,都是因为遇到了这几个异样:

  1. java.lang.NoSuchMethodException:本人代码中调用了某个办法,因为加载了其余版本的 jar,这个版本正好没这个办法。
  2. java.lang.NoClassDefFoundError:编译时候是好的,然而运行的时候,因为加载的 jar 版本问题,没有这个类。
  3. java.lang.ClassNotFoundException:在动静加载某个 Class 的时候,因为要加载的 jar 不是正确的版本,而导致找不到这个类。

当你在本地运行 ok,但到服务器上发现呈现这些谬误的时候,就要意识到很可能是 jar 抵触了(有雷同依赖存在多个版本)。这个问题往往也会有这样的体现:多实例部署的时候,有的实例是好的,有的实例则不行。

查看加载的类和办法

依据之前剖析的异样品种,咱们能够去运行中的现场确认以后加载的问题。

这里咱们能够应用阿里开源的 Arthas 工具,如果第一次用,那么按上面操作先装置再运行:

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

运行好之后,会打印出以后运行着的 java 利用,比方:

[INFO] arthas-boot version: 3.4.6
[INFO] Process 40611 already using port 3658
[INFO] Process 40611 already using port 8563
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 40611 chapter4-3-0.0.1-SNAPSHOT.jar
  [2]: 37786

通过输出编号抉择要查看的 java 利用,比方这里抉择:1,进入到 chapter4-3-0.0.1-SNAPSHOT.jar 中去。

上面介绍两个重要命令:

第一个:sc命令,咱们确认一下可能抵触的 jar 包上面,是否有对应的 class。有些不同版本包下 class 就不一样,马上就能够分辨进去。

比方,通过上面的命令,咱们查看一下 com.didispace 包下有什么类:

[arthas@40611]$ sc com.didispace.*
com.didispace.chapter43.Chapter43Application
com.didispace.chapter43.Chapter43Application$$EnhancerBySpringCGLIB$$8b82b194
com.didispace.chapter43.UploadController
Affect(row-cnt:3) cost in 6 ms.

第二个:sm命令,查看具体某个类有哪些办法。有的版本差别就是去掉了某个办法,这个时候咱们就能够通过这个命令来查看。

比方,通过上面的命令,咱们查看一下 com.didispace.chapter43.UploadController 类下有些什么办法:

[arthas@40611]$ sm com.didispace.chapter43.UploadController
com.didispace.chapter43.UploadController <init>()V
com.didispace.chapter43.UploadController create(Lorg/springframework/web/multipart/MultipartFile;)Ljava/lang/String;
com.didispace.chapter43.UploadController uploadPage()Ljava/lang/String;
Affect(row-cnt:3) cost in 5 ms.

本文首发:https://blog.didispace.com/ar…

找到抵触并解决抵触

在确认完是加载谬误的状况下,咱们要去解决抵触。那么解决抵触要做的就是找到到底哪里抵触了以及咱们要去除或者强制

找出版本抵触的办法:应用 Maven 命令:mvn -U dependency:tree -Dverbose

命令执行之后,会在控制台以树状模式列出所有依赖内容,而后通过搜寻的形式查找抵触的包,看看都是从哪个依赖中带进来的(在 IDEA 中搜寻会高亮,更容易找到)。

[INFO] com.didispace:chapter4-3:jar:0.0.1-SNAPSHOT
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.4.1:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:2.4.1:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:2.4.1:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.4.1:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.4.1:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] |  |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.13.3:compile
[INFO] |  |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.13.3:compile
[INFO] |  |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.30:compile
[INFO] |  |  +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.27:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-json:jar:2.4.1:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.11.3:compile
[INFO] |  |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.11.3:compile
[INFO] |  |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.11.3:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.11.3:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.11.3:compile
[INFO] |  |  \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.11.3:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.4.1:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.41:compile
[INFO] |  |  +- org.glassfish:jakarta.el:jar:3.0.3:compile
[INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.41:compile
[INFO] |  +- org.springframework:spring-web:jar:5.3.2:compile
[INFO] |  |  \- org.springframework:spring-beans:jar:5.3.2:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:5.3.2:compile
[INFO] |     +- org.springframework:spring-aop:jar:5.3.2:compile
[INFO] |     +- org.springframework:spring-context:jar:5.3.2:compile
[INFO] |     \- org.springframework:spring-expression:jar:5.3.2:compile
[INFO] +- org.springframework.boot:spring-boot-starter-thymeleaf:jar:2.4.1:compile
[INFO] |  +- org.thymeleaf:thymeleaf-spring5:jar:3.0.11.RELEASE:compile
[INFO] |  |  +- org.thymeleaf:thymeleaf:jar:3.0.11.RELEASE:compile
[INFO] |  |  |  +- org.attoparser:attoparser:jar:2.0.5.RELEASE:compile

解决版本抵触的形式次要两种:

  1. 通过下面的命令找到不须要的版本之后,在引入的依赖中,应用 exclusions 将其排除,比方上面这样:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    <exclusions>
        <exclusion>
            <groupId>xxx</groupId>
            <artifactId>yyy</artifactId>
        </exclusion>
    </exclusions>
</dependency>
  1. pom.xml 中强制指定要应用的版本,这样这个优先级最高,就不会引入其余版本要带进来的版本了。

好了,明天的分享到这里完结了,心愿对你有所帮忙。如果您感觉本文有用,欢送转发扩散!

欢送关注我的公众号:程序猿 DD,取得独家整顿的收费学习资源助力你的 Java 学习之路!另每周赠书不停哦~

退出移动版