<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          幾個(gè)解決 Maven Jar 包沖突的小技巧,太實(shí)用了!

          共 3099字,需瀏覽 7分鐘

           ·

          2020-08-19 19:44

          Java技術(shù)棧

          www.javastack.cn

          關(guān)注閱讀更多優(yōu)質(zhì)文章



          前言

          大家在項(xiàng)目中肯定有碰到過Maven的Jar包沖突問題,經(jīng)常出現(xiàn)的場景為:

          本地運(yùn)行報(bào)NoSuchMethodErrorClassNotFoundException。明明在依賴?yán)镉羞@個(gè)Jar包啊。怎么運(yùn)行不了!?

          項(xiàng)目中明明定義著某個(gè)jar包版本為2.0.2,怎么打包之后變成2.5.0了!?

          A項(xiàng)目引xxx.jar包運(yùn)行好好的,B項(xiàng)目同樣引入xxx.jar后,運(yùn)行報(bào)錯(cuò)了。。是B項(xiàng)目有問題,還是xxx.jar包有問題!?

          本地環(huán)境和測試環(huán)境運(yùn)行的好好的,到了生產(chǎn)就報(bào)一堆NoSuchMethodError,是我人品有問題還是生產(chǎn)環(huán)境有問題!?

          這樣的問題如果不熟悉maven依賴機(jī)制的同學(xué)排查起來,估計(jì)挺頭痛的。

          而且maven依賴結(jié)構(gòu)不好的項(xiàng)目,在引入新的Jar包時(shí)的風(fēng)險(xiǎn)也是巨大的。小則影響性能,大則引起生產(chǎn)發(fā)布和運(yùn)行時(shí)異常。

          其實(shí)以上問題的根源都來自于Maven的Jar包沖突和使用不當(dāng)?shù)囊蕾噦鬟f。這篇文章我就好好分析下以下3個(gè)內(nèi)容:

          • 依賴傳遞的原則和產(chǎn)生Jar包沖突的原理分析
          • 定位沖突以及解決Jar包沖突的幾個(gè)簡單技巧
          • 如何寫一個(gè)干凈依賴關(guān)系的POM文件

          依賴傳遞原則

          幾乎所有的Jar包沖突都和依賴傳遞原則有關(guān),所以我們先說Maven中的依賴傳遞原則:

          最短路徑優(yōu)先原則

          假如引入了2個(gè)Jar包A和B,都傳遞依賴了Z這個(gè)Jar包:

          A -> X -> Y -> Z(2.5)

          B -> X -> Z(2.0)

          那其實(shí)最終生效的是Z(2.0)這個(gè)版本。因?yàn)樗穆窂礁佣獭H绻冶镜匾昧薢(3.0)的包,那生效的就是3.0的版本。一樣的道理。

          最先聲明優(yōu)先原則

          如果路徑長短一樣,優(yōu)先選最先聲明的那個(gè)。

          A -> Z(3.0)

          B -> Z(2.5)

          這里A最先聲明,所以傳遞過來的Z選擇用3.0版本的。

          Jar包沖突的原理

          假設(shè)我們項(xiàng)目中依賴了A和B兩個(gè)Jar包。而A和B各自又有以下傳遞依賴

          A -> X -> Z(2.0)

          B -> X -> Y -> Z(2.5)

          那最終系統(tǒng)中Z包就產(chǎn)生了沖突,2.0和2.5兩個(gè)版本沖突。但是classpath中只會依賴一個(gè)版本的Z包。根據(jù)傳遞依賴的最短路徑優(yōu)先原則,最終依賴的應(yīng)該是2.0版本。

          如果Y包中用了Z包2.5版本中新的method時(shí)候,當(dāng)運(yùn)行到這段邏輯的時(shí)候。就會報(bào)NoSuchMethodError了。因?yàn)楸緛硪蕾嚨氖?.5版本,但是因?yàn)镴ar包沖突Maven選擇了2.0版本,2.0版本中又沒有這個(gè)新的method,導(dǎo)致出錯(cuò)。

          但要注意的是,不是所有沖突都會引起運(yùn)行異常。相反,大部分公司的項(xiàng)目都會有一些Jar包沖突,但其實(shí)沒有造成運(yùn)行時(shí)的問題。

          這是因?yàn)楹芏鄠鬟f依賴的Jar包,不管是2.0版本也好,2.5版本也好,都可以運(yùn)行。

          只有高版本Jar包不向下兼容,或者新增了某些低版本沒有的API才有可能導(dǎo)致這樣的問題

          定位沖突

          IDEA提供了一個(gè)maven依賴分析神器:Maven Helper

          用這個(gè)插件能很好的顯示出項(xiàng)目中所有的依賴樹和沖突

          這里面紅色高亮的部分,就表明這個(gè)Jar包有了沖突。選中這個(gè)jar包,可以看到這2個(gè)版本的沖突的來源。不會使用 IDEA 的可以關(guān)注公眾號Java技術(shù)棧在后臺回復(fù)idea,可以獲取我整理的系列 IDEA 干貨教程。

          上圖的例子,表明cruator-client這個(gè)Jar包,有2個(gè)傳遞依賴,分別為2.5.0版本和4.0.1版本。沖突的描述為:

          omitted for conflict with 2.5.0. ?由于與2.5.0版本沖突而被省略

          具體的層級在右邊也一目了然了,所以maven最終根據(jù)最短路徑優(yōu)先原則選擇了2.5.0版本,4.0.1版本被忽略。

          這時(shí)候有同學(xué)會問:本地環(huán)境我可以利用Maven Helper來定位,那么預(yù)生產(chǎn)或者生產(chǎn)環(huán)境呢。又沒有IDEA,如何定位沖突的細(xì)節(jié)?

          可以利用mvn命令來解決:

          mvn dependency:tree -Dverbose

          此處一定不要省略-Dverbose參數(shù),要不然是不會顯示被忽略的包的

          這篇《這 30 個(gè)常用的 Maven 命令》推薦看下,不會使用 Maven 的可以關(guān)注公眾號Java技術(shù)棧在后臺回復(fù)maven,可以獲取我整理的系列 Maven干貨


          其實(shí)mvn命令行一樣好用。非常清晰明確。

          解決Jar包沖突的幾個(gè)實(shí)用技巧

          排除法

          還是上面的那個(gè)例子,現(xiàn)在生效的是2.5.0,如果想生效4.0.1。只需要在2.5.0上面點(diǎn)exclude就行了。

          版本鎖定法

          如果很多個(gè)依賴都傳遞了Jar包A,涉及了很多個(gè)版本,但是你只想指定一個(gè)版本。用排除法一個(gè)個(gè)去exclude太麻煩,而且exclude在pom文件中也會體現(xiàn),太多的話,也影響代碼整潔和閱讀感受。

          這時(shí)候需要用到版本鎖定法

          何謂版本鎖定法?公司的項(xiàng)目一般都會有父級pom,你想指定哪個(gè)版本只需要在你項(xiàng)目的父POM中(當(dāng)然在本工程內(nèi)也可以)定義如下:(還是舉上個(gè)例子,指定4.0.1版本)


          ????
          ????????org.apache.curator
          ????????curator-client
          ????????4.0.1
          ????

          鎖定版本法可以打破2個(gè)依賴傳遞的原則,優(yōu)先級為最高

          鎖定版本后,依賴樹為:

          都統(tǒng)一變成4.0.1,鎖定版本有一個(gè)好處:版本鎖定并不排除Jar包,而且顯示的把所有版本不一致的Jar包變成統(tǒng)一一個(gè)版本,這樣在閱讀代碼時(shí)比較友好。也不用忍受一大堆的exclude標(biāo)簽。

          如何寫一個(gè)干凈依賴關(guān)系的POM文件

          我本人是有些輕度代碼潔癖的人,所以即便是pom文件的依賴關(guān)系也想干凈而整潔。如何寫好干凈的POM呢,作者認(rèn)為有幾點(diǎn)技巧要注意:

          • 盡量在父POM中定義,來進(jìn)行本項(xiàng)目一些依賴版本的管理,這樣可以從很大程度上解決一定的沖突
          • 如果是提供給別人依賴的Jar包,盡可能不要傳遞依賴不必要的Jar包
          • 使用mvn dependency:analyze-only命令用于檢測那些聲明了但是沒被使用的依賴,如有有一些是你自己聲明的,那盡量去掉
          • 使用mvn dependency:analyze-duplicate命令用來分析重復(fù)定義的依賴,清理那些重復(fù)定義的依賴


          最后

          其實(shí)龐大的項(xiàng)目依賴傳遞也一定多。但是不管多復(fù)雜的依賴關(guān)系,看到不要害怕。就這么幾條原則,細(xì)心的去分析,所有的依賴都有跡可循。

          這些傳遞依賴如果管理的好,能讓你的維護(hù)成本大大降低。如果管不好,這群野孩子每一個(gè)都可能是引發(fā)下一個(gè)NoSuchMethodError的導(dǎo)火索。

          最近熱文:
          1、重磅!《Java開發(fā)手冊(嵩山版)》最新發(fā)布
          2、打破你的認(rèn)知!Java空指針居然還能這樣玩
          3、盤點(diǎn) 35 個(gè) Apache 頂級項(xiàng)目,我拜服了…
          4、Spring Boot 太狠了,一次發(fā)布 3 個(gè)版本!
          5、Spring Boot 如何快速集成 Redis?
          6、盤點(diǎn) 6 個(gè)被淘汰的 Java 技術(shù),曾經(jīng)風(fēng)光過!
          7、Spring Boot Redis 實(shí)現(xiàn)分布式鎖,真香!
          8、Spring Boot 干掉了 Maven 擁抱 Gradle!
          9、公司來了個(gè)新同事不會用 Lombok!
          10、同事寫了個(gè)隱藏 bug,我排查了 3 天!
          掃碼關(guān)注Java技術(shù)棧公眾號閱讀更多干貨。

          點(diǎn)擊「閱讀原文」獲取面試題大全~

          瀏覽 44
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本一级毛片 | 黄色一级片日韩学生妹无套无码内射视频 | 日韩一级A片 | 俺去搞 | 日本免费特一级 |