Maven依賴衝突的產生緣由和解決方式

maven定義了許多dependency,每一個dependency內部也會定義它的dependency。web

首先咱們來看一下依賴衝突產生的緣由:

  1. 若是項目的依賴A和依賴B同時引入了依賴C。
  2. 若是依賴C在A和B中的版本不一致就可能依賴衝突。
  3. 好比 項目 <- A, B, A <- C(1.0),B <- C(1.1)。
  4. 那麼maven若是選擇高版本C(1.1)來導入(這個選擇maven會根據不等路徑短路徑原則和同等路徑第一聲明原則選取),C(1.0)中的類c在C(1.1)中被修改而不存在了。
  5. 在編譯期可能並不會報錯,由於編譯的目的只是把業務源代碼編譯成class文件,因此若是項目源代碼中沒有引入共有依賴C因升級而缺失的類c,就不會出現編譯失敗。除非源代碼就引入了共有依賴C因升級而缺失的類c則會直接編譯失敗。
  6. 在運行期,頗有可能出現依賴A在執行過程當中調用C(1.0)之前有可是升級到C(1.1)就缺失的類c,致使運行期失敗,出現很典型的依賴衝突時的NoClassDefFoundError錯誤。
  7. 若是是升級後出現原有的方法被修改而不存在的狀況時,就會拋出NoSuchMethodError錯誤。

那麼怎麼來解決依賴衝突呢?

  1. 首先能夠藉助Maven查看依賴的依賴樹來分析一下:mvn dependency:tree,或者使用IDEA的插件Dependency Analyzer插件來可視化地分析依賴關係。這個過程後能夠明確哪些dependency引入了可能會衝突的依賴。
  2. 好比咱們的項目引入A的依賴C爲1.1版本,引入的B會在內部依賴C的1.0版本,那麼Dependency Analyzer插件會出現依賴衝突提示,會提示B引入的C的1.0版本和當前選用的C的1.1版本衝突於是被忽略(1.0 omitted for conflict with 1.1)。
  3. 若是這時候打war包出來啓動頗有可能會遇到因依賴衝突而出現的NoClassDefFoundErrorNoSuchMethodError,致使編譯期正常的代碼沒法在運行期跑起來。
  4. 因爲A引入的C的版本高而B依賴的C版本低,咱們優先會選擇兼容高版本C的方案,即試圖把B的版本調高以使得引入的依賴C能夠和A引入的依賴A達到一致的版本,以此來解決依賴衝突。固然這是一個理想情況。
  5. 若是找到了目前已有的全部的B的版本,均發現其依賴的C沒有與A一致的1.1版本,好比B是一個許久未升級的舊項目,那麼也能夠考慮把A的版本拉低以使得C的版本降到與B一致的1.0版本,固然這也可能會反過來致使A不能正常工做。
  6. 上面已經能夠看出來解決依賴衝突這件事情並不簡單,很難顧及兩邊,不少狀況下引入不一樣版本依賴的極可能超過兩方而是更多方。
  7. 那麼來考慮一下妥協的方案,若是A引入的C使用的功能並不跟被拋棄的類或方法有關,而是其餘在1.1版本中仍然沒有改變的類或方法,那麼能夠考慮直接使用舊的1.0版本,那麼可使用exclusion標籤來在A中排除掉對C的依賴,那麼A在使用到C的功能時會使用B引入的1.0舊版本C。即A其實向B妥協使用了B依賴的C。

來看個實例:spring

  1. 項目引入了4.2.5.RELEASEspring-webmvc,同時引入了3.2.1.RELEASEspring-security-web
  2. 用Dependency Analyzer插件分析獲得的依賴關係是這樣的:

  3. 爲何maven會選擇4.2.5.RELEASE引入呢,其實前文提到過:好比對spring-beans這個依賴來講spring-webmvc:4.2.5.RELEASE-spring-beans:4.2.5.RELEASE的路徑是2,而spring-security-web:3.2.1.RELEASE-spring-security-core:3.2.1.RELEASE-spring-beans:3.2.8.RELEASE的路徑是3,所以根據不等路徑取短路徑原則則選取了前者,即spring-beans:4.2.5.RELEASE,注意的是引入時並非優先引入高版本的,同時若是依賴的路徑長相等則取第一個出現的版本。
  4. 能夠看到spring-security-web引入的一衆spring依賴是3.X版本的,同spring-webmvc4.2.5.RELEASE版本不一致。
  5. 果不其然,打好的war包啓動的時候即會報錯終止。
  6. 那麼在咱們的問題在於兼容高版本的spring-webmvc4.2.5.RELEASE的情形下尋找spring依賴版本一致的spring-security-web,在www.mvnrepository.com尋找合適版本依賴的spring-security-web,最終咱們看到了4.1.0.RELEASE版本彷佛還不錯,其依賴的spring版本在4.2.5.RELEASE

  7. 所以咱們將這個版本的spring-security-web填入pom.xml看一下效果,確實已經沒有依賴衝突產生了:

  8. 若是咱們找不到完美匹配4.2.5.RELEASEspring-security-web怎麼辦,好比全部的spring-security-web版本就是在4.2.3.RELEASE或者4.2.6.RELEASE,那麼咱們就得想到妥協一下了:使用4.1.1.RELEASE版本的spring-security-web,它的spring依賴版本是4.3.1.RELEASE

那麼咱們試圖使用exclusive標籤來忽略spring版本:express

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>4.1.1.RELEASE</version>
    <exclusions>
        <exclusion>
            <artifactId>spring-aop</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-beans</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-context</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-core</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-expression</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-web</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
    </exclusions>
</dependency>

依賴衝突會消失,spring-security-web會使用4.2.5.RELEASE版本的spring:mvc

相關文章
相關標籤/搜索