Maven--jar包衝突原理與解決辦法

Maven中jar包衝突是開發過程當中比較常見而又使人頭疼的問題,咱們須要知道 jar包衝突的原理,才能更好的去解決jar包衝突的問題。本文將從jar包衝突的原理和解決兩個方面闡述Maven中jar包衝突的解決辦法。java

1、Maven中jar包衝突產生緣由
MAVEN項目運行中若是報以下錯誤:spring

Caused by:java.lang.NoSuchMethodError Caused by: java.lang.ClassNotFoundException

十有八九是Maven jar包衝突形成的。那麼jar包衝突是如何產生的?google

首先咱們須要瞭解jar包依賴的傳遞性。spa

一、依賴傳遞
當咱們須要A的依賴的時候,就會在pom.xml中引入A的jar包;而引入的A的jar包中可能又依賴B的jar包,這樣Maven在解析pom.xml的時候,會依次將A、B 的jar包所有都引入進來。.net

舉個例子:
在Spring Boot應用中導入Hystrix和原生Guava的jar包:插件

<!--原生Guava API-->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>20.0</version>
</dependency>

<!--hystrix依賴(包含對Guava的依賴)-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>1.4.4.RELEASE</version>
</dependency>

二、jar包衝突原理

那麼jar包是如何產生衝突的? 
假設有以下依賴關係:日誌

A->B->C->D1(log 15.0):A中包含對B的依賴,B中包含對C的依賴,C中包含對D1的依賴,假設是D1是日誌jar包,version爲15.0 E->F->D2(log 16.0):E中包含對F的依賴,F包含對D2的依賴,假設是D2是同一個日誌jar包,version爲16.0

當pom.xml文件中引入A、E兩個依賴後,根據Maven傳遞依賴的原則,D一、D2都會被引入,而D一、D2是同一個依賴D的不一樣版本。
當咱們在調用D2中的method1()方法,而D1中是15.0版本(method1多是D升級後增長的方法),可能沒有這個方法,這樣JVM在加載A中D1依賴的時候,找不到method1方法,就會報NoSuchMethodError的錯誤,此時就產生了jar包衝突。code

注: 
若是在調用method2()方法的時候,D一、D2都含有這個方法(且升級的版本D2沒有改動這個方法,這樣即便D有多個版本,也不會產生版本衝突的問題。)xml

2、 Maven中jar包衝突的解決方案

Maven 解析 pom.xml 文件時,同一個 jar 包只會保留一個,那麼面對多個版本的jar包,須要怎麼解決呢?blog

一、 Maven默認處理策略

最短路徑優先

Maven 面對 D1 和 D2 時,會默認選擇最短路徑的那個 jar 包,即 D2。E->F->D2 比 A->B->C->D1 路徑短 1。

最早聲明優先

若是路徑同樣的話,如: A->B->C1, E->F->C2 ,兩個依賴路徑長度都是 2,那麼就選擇最早聲明。

二、移除依賴:用於排除某項依賴的依賴jar包

(1)咱們能夠藉助Maven Helper插件中的Dependency Analyzer分析衝突的jar包,而後在對應標紅版本的jar包上面點擊execlude,就能夠將該jar包排除出去。

(2)手動排除 
或者手動在pom.xml中使用<exclusion>標籤去排除衝突的jar包(上面利用插件Maven Helper中的execlude方法其實等同於該方法):

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        <version>1.4.4.RELEASE</version>
        <exclusions>
            <exclusion>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
            </exclusion>
    </exclusions>
</dependency>

mvn分析包衝突命令:

mvn dependency:tree

3 版本鎖定原則:通常用在繼承項目的父項目中
正常項目都是多模塊的項目,如moduleA和moduleB共同依賴X這個依賴的話,那麼能夠將X抽取出來,同時設置其版本號,這樣X依賴在升級的時候,不須要分別對moduleA和moduleB模塊中的依賴X進行升級,避免太多地方(moduleC、moduleD….)引用X依賴的時候忘記升級形成jar包衝突,這也是實際項目開發中比較常見的方法。

首先定義一個父pom.xml,將公共依賴放在該pom.xml中進行聲明:

<properties>
    <spring.version>spring4.2.4</spring.version>
<properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.versio}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

這樣如moduleA和moduleB在引用Spring-beans jar包的時候,直接使用父pom.xml中定義的公共依賴就能夠: 
moduleA在其pom.xml使用spring-bean的jar包(不用再定義版本):

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
    </dependency>
</dependencies>

 

原文:https://blog.csdn.net/noaman_wgs/article/details/81137893 

相關文章
相關標籤/搜索