今天碰到羣裏小夥伴問,線上程序好像有多個不一樣版本的Netty包,怎麼去看到底加載了哪個?java
在說如何看以前,先來講說,當你開始意識到項目裏有多個不一樣版本的Jar包,都是由於遇到了這幾個異常:web
java.lang.NoSuchMethodException
:本身代碼中調用了某個方法,由於加載了其餘版本的jar,這個版本正好沒這個方法。java.lang.NoClassDefFoundError
:編譯時候是好的,可是運行的時候,由於加載的jar版本問題,沒有這個類。java.lang.ClassNotFoundException
:在動態加載某個Class的時候,由於要加載的jar不是正確的版本,而致使找不到這個類。當你在本地運行ok,但到服務器上發現出現這些錯誤的時候,就要意識到極可能是jar衝突了(有相同依賴存在多個版本)。這個問題每每也會有這樣的表現:多實例部署的時候,有的實例是好的,有的實例則不行。spring
根據以前分析的異常種類,咱們能夠去運行中的現場確認當前加載的問題。express
這裏咱們可使用阿里開源的Arthas工具,若是第一次用,那麼按下面操做先安裝再運行:apache
curl -O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar
運行好以後,會打印出當前運行着的java應用,好比:json
[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中去。api
下面介紹兩個重要命令:tomcat
第一個:sc
命令,咱們確認一下可能衝突的jar包下面,是否有對應的class。有些不一樣版本包下class就不同,立刻就能夠分辨出來。bash
好比,經過下面的命令,咱們查看一下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.
在確認完是加載錯誤的狀況下,咱們要去解決衝突。那麼解決衝突要作的就是找到到底哪裏衝突了以及咱們要去除或者強制
找出版本衝突的方法:使用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
解決版本衝突的方式主要兩種:
exclusions
將其排除,好比下面這樣:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> <exclusions> <exclusion> <groupId>xxx</groupId> <artifactId>yyy</artifactId> </exclusion> </exclusions> </dependency>
pom.xml
中強制指定要使用的版本,這樣這個優先級最高,就不會引入其餘版本要帶進來的版本了。好了,今天的分享到這裏結束了,但願對你有所幫助。若是您以爲本文有用,歡迎轉發擴散!
歡迎關注個人公衆號:程序猿DD,得到獨家整理的免費學習資源助力你的Java學習之路!另每週贈書不停哦~