一、問題背景
相信大家在日常的開發(fā)過程中都遇到過Jar包沖突的問題,emm,在最近處理業(yè)務(wù)需求時(shí)我也遇到了不同版本jar包沖突導(dǎo)致項(xiàng)目加載出錯(cuò)的問題。主要是一個(gè)完整的項(xiàng)目會(huì)不可避免的使用第三方的Jar包來實(shí)現(xiàn)功能開發(fā),各種第三方包之間可能會(huì)存在依賴關(guān)系,不同版本的依賴就會(huì)可能導(dǎo)致依賴間的相互沖突,進(jìn)而導(dǎo)致整個(gè)項(xiàng)目加載的失敗。
這篇文章主要記錄了本次遇到的問題:即maven在面對不同版本的jar包在pom文件中同時(shí)聲明會(huì)存在加載覆蓋的問題,于是通過查詢網(wǎng)上相關(guān)資料對maven包的加載規(guī)則介紹,并通過實(shí)際場景對其進(jìn)行分析驗(yàn)證;
二、maven加載原則
1.最短路徑原則:面對多級(jí)(兩級(jí)及以上)的不同依賴,會(huì)優(yōu)先選擇路徑最短的依賴;
2.聲明優(yōu)先原則:面對多級(jí)(兩級(jí)及以上)的同級(jí)依賴,先聲明的依賴會(huì)覆蓋后聲明的依賴;
3.同級(jí)依賴中,后聲明的依賴會(huì)覆蓋先聲明的依賴;
三、本地驗(yàn)證maven加載原則
1.最短路徑原則:使用最短路徑加載的前提是,項(xiàng)目中存在兩級(jí)以上的不同依賴jar包,此時(shí)項(xiàng)目會(huì)優(yōu)先加載路徑最短的jar包;
?實(shí)例驗(yàn)證:分別在common模塊和service模塊中間接和直接的引入不同版本的elasticsearch-rest-client,觀察項(xiàng)目中面對不同路徑長度情況下實(shí)際加載時(shí)所使用的版本情況。
?common模塊:在common模塊中引入elasticsearch-rest-high-level-client 依賴包, 而該依賴包它引入了 elasticsearch-rest-client 7.4.2,從而實(shí)現(xiàn)在common模塊中間接引用該包;
common的pom文件:
org.elasticsearch.client/groupId?> elasticsearch-rest-high-level-client/artifactId?> 7.4.2/version?> /dependency?> /dependencies?>
?service模塊:為了驗(yàn)證不同路徑長度下maven的包加載順序,我們在service模塊中直接引入elasticsearch-rest-client 6.8.13;
service的pom文件:
org.elasticsearch.client/groupId?> elasticsearch-rest-client/artifactId?> 6.8.13/version?> /dependency?> /dependencies?>
?實(shí)際加載結(jié)果:在IDEA中加載pom文件時(shí),可以在maven管理中看到已經(jīng)提示jar包沖突;
?mvn dependency:tree: 我們可以通過mvn dependency :tree命令來查看該項(xiàng)目的依賴樹,觀察發(fā)現(xiàn)實(shí)際加載的版本是elasticsearch-rest-client 6.8.13,符合maven中的最短路徑優(yōu)先原則;
?
2. 聲明優(yōu)先原則:聲明優(yōu)先原則的前提是對于兩級(jí)以上的同級(jí)依賴,先聲明的依賴會(huì)覆蓋后聲明的依賴包;
?實(shí)例驗(yàn)證:針對該原則的驗(yàn)證場景構(gòu)造不再關(guān)注模塊是否直接或者間接引用不同版本的es,我們在common模塊和service模塊中都直接引用不同版本的es,然后通過改變兩個(gè)模塊在pom文件中聲明的先后順序來觀察項(xiàng)目啟動(dòng)后實(shí)際加載的jar包;
?common模塊:在common模塊中直接引入依賴包elasticsearch-rest-client 7.4.2
org.elasticsearch.client/groupId?> elasticsearch-rest-client/artifactId?> 7.4.2/version?> /dependency?> /dependencies?>
?service模塊:在service模塊中引入依賴包elasticsearch-rest-client 6.8.13
org.elasticsearch.client/groupId?> elasticsearch-rest-client/artifactId?> 6.8.13/version?> /dependency?> /dependencies?>
?實(shí)際加載結(jié)果:
?場景1:我們將common模塊在pom文件中先引入,然后將在service模塊置于common模塊后面引入,觀察項(xiàng)目實(shí)際加載情況;
org.example/groupId?> backend_common/artifactId?> 1.0-SNAPSHOT/version?> /dependency?> org.example/groupId?> backend_service/artifactId?> 1.0-SNAPSHOT/version?> /dependency?> /dependencies?>
?觀察加載結(jié)果圖,發(fā)現(xiàn)實(shí)際加載的是es-rest-client 7.4.2, 即確實(shí)是common模塊的聲明生效,service模塊后聲明導(dǎo)致其中的es未被加載。符合聲明優(yōu)先原則;
?場景2:我們將service模塊在pom文件中先引入,然后將在common模塊置于service模塊后面引入,觀察項(xiàng)目實(shí)際加載情況;;
org.example/groupId?> backend_service/artifactId?> 1.0-SNAPSHOT/version?> /dependency?> org.example/groupId?> backend_common/artifactId?> 1.0-SNAPSHOT/version?> /dependency?> /dependencies?>
?觀察項(xiàng)目實(shí)際加載結(jié)果圖,發(fā)現(xiàn)實(shí)際加載的是es-rest-client 6.8.13, 即確實(shí)是模塊的聲明生效,common模塊后聲明導(dǎo)致其中的es未被加載。發(fā)現(xiàn)符合聲明優(yōu)先原則;
?聲明優(yōu)先原則場景驗(yàn)證結(jié)束;
3. 同級(jí)依賴中后加載覆蓋先加載原則;
?實(shí)例驗(yàn)證:為了構(gòu)造在同級(jí)依賴中的加載場景,我們在項(xiàng)目中直接引入兩個(gè)不同es版本的依賴,然后同樣通過改變兩個(gè)es版本在pom中的聲明順序來觀察項(xiàng)目實(shí)際加載的es版本。
?場景1:我們首先驗(yàn)證client 7.4.2依賴包在client 6.8.13之前聲明的情況;
org.elasticsearch.client/groupId?> elasticsearch-rest-client/artifactId?> 7.4.2/version?> /dependency?> org.elasticsearch.client/groupId?> elasticsearch-rest-client/artifactId?> 6.8.13/version?> /dependency?> /dependencies?>
?觀察maven的實(shí)際加載結(jié)果如下,發(fā)現(xiàn)項(xiàng)目中實(shí)際加載的es-rest-client 版本是6.8.13,先聲明的7.4.2版本并未實(shí)際加載到項(xiàng)目中。符合同級(jí)依賴中后加載覆蓋先加載原則。
?場景2:然后我們改變聲明順序,將client 6.8.13依賴包在client 7.4.2之前聲明;
org.elasticsearch.client/groupId?> elasticsearch-rest-client/artifactId?> 6.8.13/version?> /dependency?> org.elasticsearch.client/groupId?> elasticsearch-rest-client/artifactId?> 7.4.2/version?> /dependency?> /dependencies?>
?觀察maven實(shí)際加載結(jié)果如下,發(fā)現(xiàn)項(xiàng)目中實(shí)際加載的es-rest-client 版本是7.4.2,先聲明的6.8.13版本并未實(shí)際加載到項(xiàng)目中。符合同級(jí)依賴中后加載覆蓋先加載原則。
四、常見異常
Jar發(fā)生沖突后在程序啟動(dòng)時(shí)常見異常報(bào)錯(cuò),下面四種異常是能夠直觀表征Jar包加載沖突:
?程序拋出java.lang.ClassNotFoundException異常;
?程序拋出java.lang.NoSuchMethodError異常;
?程序拋出java.lang.NoClassDefFoundError異常;
?程序拋出java.lang.LinkageError異常等;
五、總結(jié)
之前只是淺層的了解maven包的加載,沒有結(jié)合具體的加載原則進(jìn)行系統(tǒng)的學(xué)習(xí)驗(yàn)證,正好通過需求開發(fā)中遇到依賴沖突相關(guān)問題對maven的加載原則進(jìn)行探究。ok,明白啦!
審核編輯 黃宇
-
maven
+關(guān)注
關(guān)注
0文章
30瀏覽量
3713
發(fā)布評(píng)論請先 登錄
相關(guān)推薦
評(píng)論