jar依賴沖突解決實踐
隨著功能的增多,各種中間件的引入陶珠。應用以來的各種jar的規(guī)模極具膨脹柔逼,出現(xiàn)jar沖突和Class沖突的問題層出不窮蒋譬,讓人不勝其擾。本文針對沖突愉适,提供一個排查和定位問題的最佳實踐犯助。實踐中盡量不借助第三方工具,而使用maven或者Linux的自帶命令行儡毕。
Maven構(gòu)建的應用的jar沖突
目前最為最流行的項目構(gòu)建和管理工具也切,在目前的互聯(lián)網(wǎng)應用中被廣泛使用扑媚。maven框架很大的一個便利就是對于jar的依賴管理腰湾,它自然提供了一些工具幫助開發(fā)者進行依賴分析。maven存在坐標的概念疆股。groupId费坊,artifactId,version三個維度定位到一個唯一的jar旬痹。
1
2
3
4
5
6
7com.taobao.diamonddiamond-client3.6.0jarcompile
對于版本附井,有一個很寬泛的范圍
[3.6.0,4.0.0)?要求的依賴版本>=3.6.0且<4.0.0
[,3.6.0]?要求的依賴版本<=3.6.0
對于應用來講,還是固定一個版本為好两残,夸版本有太多不可預知的情況存在永毅。
靜態(tài)代碼檢查
通過mvn dependency:tree 命令查看依賴樹
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16[INFO] \-com.alibaba.china.shared:credit_shared.ruleengine.biz:jar:1.0-SNAPSHOT:compile[INFO]? ? +-com.alibaba.china.shared:credit_shared.ruleengine.api:jar:1.0-SNAPSHOT:compile[INFO]? ? +-com.alibaba.china.shared:credit_shared.ruleengine.dal:jar:1.0-SNAPSHOT:compile[INFO]? ? +- org.antlr:antlr:jar:3.3:compile[INFO]? ? +- org.antlr:antlr-runtime:jar:3.3:compile[INFO]? ? |? \- org.antlr:stringtemplate:jar:3.2.1:compile[INFO]? ? +- org.mvel:mvel2:jar:2.1.3.Final:compile[INFO]? ? +- org.drools:knowledge-api:jar:5.5.0.Final:compile[INFO]? ? +- org.drools:drools-core:jar:5.5.0.Final:compile[INFO]? ? |? \- org.drools:knowledge-internal-api:jar:5.5.0.Final:compile[INFO]? ? \- org.drools:drools-compiler:jar:5.5.0.Final:compile[INFO]? ? ? +- org.antlr:antlr:jar:2.7.7:compile[INFO]? ? ? +- org.eclipse.jdt.core.compiler:ecj:jar:3.5.1:compile[INFO]? ? ? \-com.thoughtworks.xstream:xstream:jar:1.4.1:compile[INFO]? ? ? ? ? +- xmlpull:xmlpull:jar:1.1.3.1:compile[INFO]? ? ? ? ? \- xpp3:xpp3_min:jar:1.1.4c:compile
通過靜態(tài)代碼掃描的方式,能分析出來jar之間的依賴關系人弓。舉例credit_shared.ruleengine.biz-1.0-SNAPSHOT.jar依賴了antlr-3.3.jar沼死。org.antlr:antlr-3.3.jar在maven中的坐標是
1
2
3
4
5
6
7org.antlrantlr3.3jarcompile
依賴仲裁
從上面的依賴樹,出現(xiàn)了另外一個版本的jar——org.antlr:antlr:jar:2.7.7:compile崔赌,這就出現(xiàn)了依賴仲裁的問題意蛀。
maven 2.2.1版本仲裁規(guī)則:
按照項目總POM的DependencyManager版本聲明進行仲裁(覆蓋),但無警告
如無仲裁聲明,則按照依賴最短路徑確定版本
若相同路徑,有嚴格區(qū)間限定的版本優(yōu)先
若相同路徑,無版本區(qū)間,則按照先入為主原則
如要解決沖突問題耸别,很多時候都用到exclusions,如A->B->D(v1),A->C-D(v2),要指定A->D(v1),則需要在聲明C的依賴時候通過exclusions列表排除掉對D(v2)的依賴。
要更好理解依賴仲裁县钥,需要了解以下附帶知識秀姐。
maven classpath
maven中有三種classpath:
編譯classpath:編譯項目代碼,依賴的jar會被引入到classpath
測試classpath:編譯和執(zhí)行測試部分代碼若贮,如單元測試省有,集成測試,依賴會被引入到classpath
運行classpath:實際運行代碼的時候兜看,依賴的jar會被引入到classpath
scope:依賴范圍
scope就是為了解決jar在classpath中的可見性锥咸。scope有以下幾個可選項
compile:默認值,對編譯classpath细移、測試classpath搏予、運行classpath都有效,在三個階段都需要指定的jar
provided:編譯和測試可用弧轧,不會被傳遞依賴雪侥,不會被打包。例:依賴于web容器中的提供的一個jar包精绎,在編譯的時候需要加入依賴(web容器還沒有介入)速缨,運行的時候由web容器來提供。如servlet-api代乃。
test:執(zhí)行單元測試時可用旬牲,不會被打包,不會被傳遞依賴
runtime:運行和測試時需要搁吓,但編譯時不需要原茅。最典型的例子是JDBC的驅(qū)動,編譯時只需要提供驅(qū)動的API即可堕仔,在運行和測試階段擂橘,需要加載到具體的驅(qū)動實現(xiàn)。
system:跟provided一致摩骨,顯示制定依賴路徑通贞,一般是指定了本地的倉庫之外的類庫文件∧瘴澹可能造成不可依賴性昌罩,不推薦使用。
傳遞性依賴
A->B,B->C,則A->C灾馒。這是傳遞性依賴茎用。依賴是有范圍的,A->B,B->C的依賴范圍決定了A->C的依賴范圍。
A->Ccompileprovidedtestruntime
compilecompileruntime
providedprovidedprovidedprovided
testtesttest
runtimeruntimeruntime
可選依賴
1
2
3
4
5
6
7
8org.antlrantlr3.3jarcompiletrue
A->B,B->C(可選),B->D(可選)绘搞,則A不會通過傳遞依賴到C或者D彤避。
非Maven項目或者不同坐標的jar出現(xiàn)Class沖突,
上面介紹的是jar相同而版本不同,如antlr-3.3.jar,antlr-3.2.jar類似情況的沖突解決方案夯辖。這種情況一般出現(xiàn)在中間件升級琉预。下面介紹坐標不同,如antlr-old-3.3.jar蒿褂、antlr-new.jar,而jar中包含了類路徑完全相同的類的情況圆米。
出現(xiàn)這種情況,一般的異常提示都是“XXX類has no such method XXXX”之類的啄栓。這些異常提示基本可以定位成Class不是你要的Class娄帖,只不過Class的全路徑是相同的,最大的可能也就是ClassLoader加載了另外一個jar的同名類昙楚。所以近速,首先要排查到該類是從哪個具體jar中來的。JVM提供了這樣的功能堪旧,查看加載類的情況
1
java -verbose:class
類加載情況削葱,如SubscriptionInfo類加載自file:/home/zhao/web-deploy/jettyserver/tmp/jetty-0.0.0.0-34200-root.war--any-/webinf/WEB-INF/lib/pc2.common-1.2.5.jar
1
2[Loadedcom.alibaba.pc2.common.remote.subscription.SubscriptionInfo from file:/home/zhao/web-deploy/jetty_server/tmp/jetty-0.0.0.0-34200-root.war-_-any-/webinf/WEB-INF/lib/pc2.common-1.2.5.jar][Loadedcom.alibaba.pc2.common.domain.productpackage.PackageInfo from file:/home/zhao/web-deploy/jetty_server/tmp/jetty-0.0.0.0-34200-root.war-_-any-/webinf/WEB-INF/lib/pc2.common-1.2.5.jar]
而同樣在pmap pid可以進程的內(nèi)存鏡像。 jps -v查看pid淳梦,再通過pmap pid > map.txt,從map.txt中查到
1
00007fa4ae17400020K r-xs-? /home/zhao/web-deploy/jetty_server/tmp/jetty-0.0.0.0-34200-root.war-_-any-/webinf/WEB-INF/lib/pc2.common-1.2.5.jar
得到確認后析砸,如果是maven工程,則通過依賴樹查詢到是具體哪個jar依賴了這個錯誤引用爆袍,在pom文件中exclusions掉該jar即可首繁。
如果是非maven工程,則通過其他方式把錯誤引用排除掉即可陨囊。