Maven类包冲突终极解决小技若干
生活随笔
收集整理的這篇文章主要介紹了
Maven类包冲突终极解决小技若干
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
那句話怎么講來著的...
?
引用 如果你愛他,就請讓他用Maven,因為那里是天堂,如果你恨他,就請讓他用Maven,因為那里是地獄.
Maven對于新手來說是《步步驚心》,因為它包羅萬象,博大精深,因為當你初來乍到時,你就像一個進入森林的陌生訪客一樣迷茫。?
Maven對于老手來說是《真愛配方》,因為它無所不能,利如刀鋒,使用Maven做開發,如飲美酒如悅美人。?
Maven對于新手來說,最痛苦的一件事莫過于包之間的沖突,由于Maven的依賴傳遞性,當你引入一個依賴類時,其身后的依賴類也一起如過江之鯽紛至沓來了。?
舉個栗子 ?
A依賴于B及C,而B又依賴于X、Y,而C依賴于X、M,則A除引B及C的依賴包下,還會引入X,Y,M的依賴包(一般情況下了,Maven可通過<scope>等若干種方式控制傳遞依賴)。?
這里有一個需要特別注意的,即B和C同時依賴于X,假設B依賴于X的1.0版本,而C依賴于X的2.0版本,A究竟依賴于X的1.0還是2.0版本呢??
這就看Classloader的加載順序了,假設Classloader先加載X_1.0,而它就不會再加載X_2.0了,如果A恰恰希望使用X_2.0呢,血案就這樣不期而遇了。?
我常掄的三板斧 ?
第一板斧:找到傳遞依賴的鬼出在哪里? ?
dependency:tree 是把照妖照,pom.xml用它照照,所有傳遞性依賴都將無處遁形,并且會以層級樹方式展現,非常直觀。?
以下就是執行 dependency:tree 后的一個輸出:?
引用
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ euler-foundation ---?
[INFO] com.hsit:euler-foundation:jar:0.9.0.1-SNAPSHOT?
[INFO] +- com.rop:rop:jar:1.0.1:compile?
[INFO] |? +- org.slf4j:slf4j-api:jar:1.7.5:compile?
[INFO] |? +- org.slf4j:slf4j-log4j12:jar:1.7.5:compile?
[INFO] |? +- log4j:log4j:jar:1.2.16:compile?
[INFO] |? +- commons-lang:commons-lang:jar:2.6:compile?
[INFO] |? +- commons-codec:commons-codec:jar:1.6:compile?
[INFO] |? +- javax.validation:validation-api:jar:1.0.0.GA:compile?
[INFO] |? +- org.hibernate:hibernate-validator:jar:4.2.0.Final:compile?
[INFO] |? +- org.codehaus.jackson:jackson-core-asl:jar:1.9.5:compile?
[INFO] |? +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.5:compile?
[INFO] |? +- org.codehaus.jackson:jackson-jaxrs:jar:1.9.5:compile?
[INFO] |? +- org.codehaus.jackson:jackson-xc:jar:1.9.5:compile?
[INFO] |? \- com.fasterxml.jackson.dataformat:jackson-dataformat-xml:jar:2.2.3:compile?
[INFO] |???? +- com.fasterxml.jackson.core:jackson-core:jar:2.2.3:compile?
[INFO] |???? +- com.fasterxml.jackson.core:jackson-annotations:jar:2.2.3:compile?
[INFO] |???? +- com.fasterxml.jackson.core:jackson-databind:jar:2.2.3:compile?
[INFO] |???? +- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.2.3:compile?
[INFO] |???? \- org.codehaus.woodstox:stax2-api:jar:3.1.1:compile?
[INFO] |??????? \- javax.xml.stream:stax-api:jar:1.0-2:compile?
???? 剛才吹噓 dependency:tree 時,我用到了“無處遁形”,其實有時你會發現簡單地用 dependency:tree 往往并不能查看到所有的傳遞依賴。不過如果你真的想要看所有的,必須得加一個 -Dverbose 參數,這時就必定是最全的了。?
??? 全是全了,但顯示出來的東西太多,頭暈目眩,有沒有好法呢?當然有了,加上 Dincludes 或者 Dexcludes 說出你喜歡或討厭, dependency:tree 就會幫你過濾出來:?
引用 Dincludes=org.springframework:spring-tx
?? 過濾串使用groupId:artifactId:version的方式進行過濾,可以不寫全啦,如:?
Java代碼?? mvn?dependency:tree?-Dverbose?-Dincludes=asm:asm??
?? 就會出來asm依賴包的分析信息:?
引用
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ ridge-test ---?
[INFO] com.ridge:ridge-test:jar:1.0.2-SNAPSHOT?
[INFO] +- asm:asm:jar:3.2:compile?
[INFO] \- org.unitils:unitils-dbmaintainer:jar:3.3:compile?
[INFO]??? \- org.hibernate:hibernate:jar:3.2.5.ga:compile?
[INFO]?????? +- cglib:cglib:jar:2.1_3:compile?
[INFO]?????? |? \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)?
[INFO]?????? \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)?
[INFO] ------------------------------------------------------------------------?
?? 對asm有依賴有一個直接的依賴(asm:asm:jar:3.2)還有一個傳遞進入的依賴(asm:asm:jar:1.5.3)?
第二板斧:將不想要的傳遞依賴剪除掉 ?
?? 承上,假設我們不希望asm:asm:jar:1.5.3出現,根據分析,我們知道它是經由org.unitils:unitils-dbmaintainer:jar:3.3引入的,那么在pom.xml中找到這個依賴,做其它的調整:?
Xml代碼?? <dependency>?? ????<groupId>org.unitils</groupId>?? ????<artifactId>unitils-dbmaintainer</artifactId>?? ????<version>${unitils.version}</version>?? ????<exclusions>?? ????????<exclusion>?? ????????????<artifactId>dbunit</artifactId>?? ????????????<groupId>org.dbunit</groupId>?? ????????</exclusion>?? ????????<!--?這個就是我們要加的片斷?-->?? ????????<exclusion>?? ????????????<artifactId>asm</artifactId>?? ????????????<groupId>asm</groupId>?? ????????</exclusion>?? ????</exclusions>?? </dependency>??
?? 再分析一下,你可以看到傳遞依賴沒有了:?
Xml代碼?? [INFO]?? [INFO]?---?maven-dependency-plugin:2.1:tree?(default-cli)?@?ridge-test?---?? [INFO]?com.ridge:ridge-test:jar:1.0.2-SNAPSHOT?? [INFO]?\-?asm:asm:jar:3.2:compile?? [INFO]?------------------------------------------------------------------------?? [INFO]?BUILD?SUCCESS??
第三板斧:查看運行期類來源的JAR包 ?
有時,你以為解決了,但是偏偏還是報類包沖突(典型癥狀是java.lang.ClassNotFoundException或Method不兼容等異常),這時你可以設置一個斷點,在斷點處通過下面這個我做的工具類來查看Class所來源的JAR包:?
Java代碼?? package?com.ridge.util;?? ?? import?java.io.File;?? import?java.net.MalformedURLException;?? import?java.net.URL;?? import?java.security.CodeSource;?? import?java.security.ProtectionDomain;?? ?? /**? ?*?@author?:?chenxh? ?*?@date:?13-10-31? ?*/?? public?class?ClassLocationUtils?{?? ?? ????/**? ?????*?獲取類所有的路徑? ?????*?@param?cls? ?????*?@return? ?????*/?? ????public?static?String?where(final?Class?cls)?{?? ????????if?(cls?==?null)throw?new?IllegalArgumentException("null?input:?cls");?? ????????URL?result?=?null;?? ????????final?String?clsAsResource?=?cls.getName().replace('.',?'/').concat(".class");?? ????????final?ProtectionDomain?pd?=?cls.getProtectionDomain();?? ????????if?(pd?!=?null)?{?? ????????????final?CodeSource?cs?=?pd.getCodeSource();?? ????????????if?(cs?!=?null)?result?=?cs.getLocation();?? ????????????if?(result?!=?null)?{?? ????????????????if?("file".equals(result.getProtocol()))?{?? ????????????????????try?{?? ????????????????????????if?(result.toExternalForm().endsWith(".jar")?||?? ????????????????????????????????result.toExternalForm().endsWith(".zip"))?? ????????????????????????????result?=?new?URL("jar:".concat(result.toExternalForm())?? ????????????????????????????????????.concat("!/").concat(clsAsResource));?? ????????????????????????else?if?(new?File(result.getFile()).isDirectory())?? ????????????????????????????result?=?new?URL(result,?clsAsResource);?? ????????????????????}?? ????????????????????catch?(MalformedURLException?ignore)?{}?? ????????????????}?? ????????????}?? ????????}?? ????????if?(result?==?null)?{?? ????????????final?ClassLoader?clsLoader?=?cls.getClassLoader();?? ????????????result?=?clsLoader?!=?null???? ????????????????????clsLoader.getResource(clsAsResource)?:?? ????????????????????ClassLoader.getSystemResource(clsAsResource);?? ????????}?? ????????return?result.toString();?? ????}?? ?? }??
隨便寫一個測試,設置好斷點,在執行到斷點處按alt+F8動態執行代碼(intelij idea),假設我們輸入:?
Java代碼?? ClassLocationUtils.where(org.objectweb.asm.ClassVisitor.class)??
即可馬上查出類對應的JAR了:?
這就是org.objectweb.asm.ClassVisitor類在運行期對應的JAR包,如果這個JAR包版本不是你期望你,就說明是你的IDE緩存造成的,這時建議你Reimport一下maven列表就可以了,如下所示(idea):?
?
引用 如果你愛他,就請讓他用Maven,因為那里是天堂,如果你恨他,就請讓他用Maven,因為那里是地獄.
Maven對于新手來說是《步步驚心》,因為它包羅萬象,博大精深,因為當你初來乍到時,你就像一個進入森林的陌生訪客一樣迷茫。?
Maven對于老手來說是《真愛配方》,因為它無所不能,利如刀鋒,使用Maven做開發,如飲美酒如悅美人。?
Maven對于新手來說,最痛苦的一件事莫過于包之間的沖突,由于Maven的依賴傳遞性,當你引入一個依賴類時,其身后的依賴類也一起如過江之鯽紛至沓來了。?
舉個栗子 ?
A依賴于B及C,而B又依賴于X、Y,而C依賴于X、M,則A除引B及C的依賴包下,還會引入X,Y,M的依賴包(一般情況下了,Maven可通過<scope>等若干種方式控制傳遞依賴)。?
這里有一個需要特別注意的,即B和C同時依賴于X,假設B依賴于X的1.0版本,而C依賴于X的2.0版本,A究竟依賴于X的1.0還是2.0版本呢??
這就看Classloader的加載順序了,假設Classloader先加載X_1.0,而它就不會再加載X_2.0了,如果A恰恰希望使用X_2.0呢,血案就這樣不期而遇了。?
我常掄的三板斧 ?
第一板斧:找到傳遞依賴的鬼出在哪里? ?
dependency:tree 是把照妖照,pom.xml用它照照,所有傳遞性依賴都將無處遁形,并且會以層級樹方式展現,非常直觀。?
以下就是執行 dependency:tree 后的一個輸出:?
引用
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ euler-foundation ---?
[INFO] com.hsit:euler-foundation:jar:0.9.0.1-SNAPSHOT?
[INFO] +- com.rop:rop:jar:1.0.1:compile?
[INFO] |? +- org.slf4j:slf4j-api:jar:1.7.5:compile?
[INFO] |? +- org.slf4j:slf4j-log4j12:jar:1.7.5:compile?
[INFO] |? +- log4j:log4j:jar:1.2.16:compile?
[INFO] |? +- commons-lang:commons-lang:jar:2.6:compile?
[INFO] |? +- commons-codec:commons-codec:jar:1.6:compile?
[INFO] |? +- javax.validation:validation-api:jar:1.0.0.GA:compile?
[INFO] |? +- org.hibernate:hibernate-validator:jar:4.2.0.Final:compile?
[INFO] |? +- org.codehaus.jackson:jackson-core-asl:jar:1.9.5:compile?
[INFO] |? +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.5:compile?
[INFO] |? +- org.codehaus.jackson:jackson-jaxrs:jar:1.9.5:compile?
[INFO] |? +- org.codehaus.jackson:jackson-xc:jar:1.9.5:compile?
[INFO] |? \- com.fasterxml.jackson.dataformat:jackson-dataformat-xml:jar:2.2.3:compile?
[INFO] |???? +- com.fasterxml.jackson.core:jackson-core:jar:2.2.3:compile?
[INFO] |???? +- com.fasterxml.jackson.core:jackson-annotations:jar:2.2.3:compile?
[INFO] |???? +- com.fasterxml.jackson.core:jackson-databind:jar:2.2.3:compile?
[INFO] |???? +- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.2.3:compile?
[INFO] |???? \- org.codehaus.woodstox:stax2-api:jar:3.1.1:compile?
[INFO] |??????? \- javax.xml.stream:stax-api:jar:1.0-2:compile?
???? 剛才吹噓 dependency:tree 時,我用到了“無處遁形”,其實有時你會發現簡單地用 dependency:tree 往往并不能查看到所有的傳遞依賴。不過如果你真的想要看所有的,必須得加一個 -Dverbose 參數,這時就必定是最全的了。?
??? 全是全了,但顯示出來的東西太多,頭暈目眩,有沒有好法呢?當然有了,加上 Dincludes 或者 Dexcludes 說出你喜歡或討厭, dependency:tree 就會幫你過濾出來:?
引用 Dincludes=org.springframework:spring-tx
?? 過濾串使用groupId:artifactId:version的方式進行過濾,可以不寫全啦,如:?
Java代碼??
?? 就會出來asm依賴包的分析信息:?
引用
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ ridge-test ---?
[INFO] com.ridge:ridge-test:jar:1.0.2-SNAPSHOT?
[INFO] +- asm:asm:jar:3.2:compile?
[INFO] \- org.unitils:unitils-dbmaintainer:jar:3.3:compile?
[INFO]??? \- org.hibernate:hibernate:jar:3.2.5.ga:compile?
[INFO]?????? +- cglib:cglib:jar:2.1_3:compile?
[INFO]?????? |? \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)?
[INFO]?????? \- (asm:asm:jar:1.5.3:compile - omitted for conflict with 3.2)?
[INFO] ------------------------------------------------------------------------?
?? 對asm有依賴有一個直接的依賴(asm:asm:jar:3.2)還有一個傳遞進入的依賴(asm:asm:jar:1.5.3)?
第二板斧:將不想要的傳遞依賴剪除掉 ?
?? 承上,假設我們不希望asm:asm:jar:1.5.3出現,根據分析,我們知道它是經由org.unitils:unitils-dbmaintainer:jar:3.3引入的,那么在pom.xml中找到這個依賴,做其它的調整:?
Xml代碼??
?? 再分析一下,你可以看到傳遞依賴沒有了:?
Xml代碼??
第三板斧:查看運行期類來源的JAR包 ?
有時,你以為解決了,但是偏偏還是報類包沖突(典型癥狀是java.lang.ClassNotFoundException或Method不兼容等異常),這時你可以設置一個斷點,在斷點處通過下面這個我做的工具類來查看Class所來源的JAR包:?
Java代碼??
隨便寫一個測試,設置好斷點,在執行到斷點處按alt+F8動態執行代碼(intelij idea),假設我們輸入:?
Java代碼??
即可馬上查出類對應的JAR了:?
這就是org.objectweb.asm.ClassVisitor類在運行期對應的JAR包,如果這個JAR包版本不是你期望你,就說明是你的IDE緩存造成的,這時建議你Reimport一下maven列表就可以了,如下所示(idea):?
?
Reimport一下,IDE會強制根據新的pom.xml設置重新分析并加載依賴類包,以得到和pom.xml設置相同的依賴。(這一步非常重要哦,經常項目組pom.xml是相同的,但是就是有些人可以運行,有些人不能運行,俗稱人品問題,其實都是IDE的緩存造成的了?)?
from:?http://stamen.iteye.com/blog/2030552
總結
以上是生活随笔為你收集整理的Maven类包冲突终极解决小技若干的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 注解深入理解
- 下一篇: Apache Maven 入门篇