【maven】pom.xml文件中jar包版本衝突解決的四種方式

pom.xml 添加一個spring-context的jar包

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency>

在左邊External Libraibraries看到依賴了好幾個包

右邊Maven視窗打開依賴圖[Show Dependencies] 

此時,在pom.xml 再添加一個spring-beans的jar包,注意版本是4.2.4.RELEASE

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>

此時發現External Libraibraries顯示的依賴包中spring-beans的版本發生了變化,但spring-beans所依賴的另一個spring-core的版本卻沒有發生變化。

再打開依賴圖[Show Dependencies] ,發現此時的兩個同樣的jar包spring-beans版本是有衝突的,而且兩個spring-beans所依賴的spring-core包版本也不同。我們發現maven最後選擇的是4.2.4.RELEASEspring-beans5.2.4.RELEASEspring-core。那maven到底是如何來解決jar包版本衝突問題的呢?


maven工程要導入jar包的座標,就必須要考慮解決jar包版本衝突的問題。 主要有四種解決方式。

#1->第一聲明優先原則

pom.xml文件按從上至下的順序,哪個jar包的座標在上面,這個jar包就是先聲明的。先聲明的jar包座標下的依賴jar包,可以優先進入項目中。

例如,現在的pom.xml中關於spring-beans和spring-context順序是這樣的。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>

spring-context先聲明,spring-beans後聲明,因此它們共同依賴的spring-core包最終選擇的是和spring-context版本保持一致的5.2.4.RELEASE。

現在如果將spring-context和spring-beans的聲明順序調換一下

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>
    
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency>

這裏的spring-core版本就變成和spring-beans保持一致的4.2.4.RELEASE了。

 


關於maven導入jar包的兩個概念

[直接依賴] 項目中直接導入的jar包,就是該項目的直接依賴包。

[傳遞依賴] 項目中沒有直接導入的jar包,可以通過項目直接依賴的jar包傳遞到項目中去。

例如這個項目中直接依賴spring-contextspring-beans兩個jar包,這兩個jar包所依賴的spring-core就屬於傳遞依賴包。


 

 #2->路徑近者優先原則 

直接依賴路徑比傳遞依賴路徑近,那麼最終項目進入的jar包是路徑更近的直接依賴包。

例如,此時pom.xml再添加一個5.1.0.RELEASE的spring-core

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.1.0.RELEASE</version>
</dependency>

-> spring-context 5.2.4.RELEASE 會依賴一個 spring-core 5.2.4.RELEASE [傳遞依賴路徑]

-> spring-beans 4.2.4.RELEASE 會依賴一個 spring-core 4.2.4.RELEASE [傳遞依賴路徑]

-> spring-core 5.1.0.RELEASE [直接依賴路徑]

所以最終[直接依賴路徑]的 spring-core 5.1.0.RELEASE 成功進入了項目中,幹掉了上面兩個傳遞依賴路徑進來的jar包。

 

 #3->直接排除法

當需要排除某個jar包下的依賴包,如這裏想排除掉spring-beans 4.2.4.RELEASE所依賴的spring-core 4.2.4.RELEASE時,可以通過配置<exclusion></exclusion>標籤,將不需要的jar包排除掉。

注意標籤內部不需要寫明版本號,原因是這裏的依賴包默認版本和直接依賴包的版本是保持一致的,意思就是說,這裏所依賴的spring-core的版本只可能是4.2.4.RELEASE,沒有其他可能。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.2.4.RELEASE</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency>

按照聲明第一的原則,spring-core的版本應該會和優先聲明的spring-beans的版本保持一致,但添加<exclusion></exclusion>標籤將這一版本中的spring-core排除掉之後,最終引入項目的就是spring-context中所依賴的spring-core了。

 

 #4->鎖定jar包法(推薦方法) 

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency>

當如上聲明jar包的時候,spring-beans由於直接依賴關係,引入項目的spring-beans.jar包版本是4.2.4.RELEASE,spring-beans和spring-context共同傳遞依賴的jar包spring-core,由於要和4.2.4.RELEASE聲明優先原則而保持一致, 所以最終引入項目的spring-core的jar包版本也是4.2.4.RELEASE。

現在爲了使得spring-core最終引入項目的版本也是5.2.4.RELEASE,可以使用<dependencyManagement></dependencyManagement>標籤進行jar包的版本鎖定。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.4.RELEASE</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.4.RELEASE</version>
    </dependency>
</dependencies>

當通過標籤<dependencyManagement></dependencyManagement>對jar包版本進行鎖定之後,引入項目最終的jar包版本就以這個標籤中最終聲明的版本號爲準。需要注意的是,這個標籤內只是對jar包的版本號進行了聲明,並沒有直接將jar包引入項目中,所以下面真正聲明jar包座標的<dependency></dependency>標籤不能省略

這個鎖定jar包版本的方法還可以用於另一種情況下。

maven工程是可以分爲父子依賴關係的。凡是依賴別的項目後,項目裏引入的所依賴這個項目的所有依賴jar包,都屬於傳遞依賴

比如,當前的項目A,被項目B所依賴(B -> A),那麼項目A中所有的jar包都會傳遞到項目B中。項目B的開發者,如果再次在項目中導入一套和項目A一樣的jar包(假如他們都共同使用了SSM框架的一套jar包),對於項目B來說這些重新導入的jar包都是直接依賴關係,那麼直接依賴的jar包就會把從項目A傳遞過去的jar包直接覆蓋掉。這裏就會出現問題,項目A使用的jar包版本比項目B高,這樣項目B直接覆蓋掉原有的傳遞依賴包,項目可能就無法運行了,這不是我們希望出現的情況。

因此,爲了防止這樣的情況出現,可以通過標籤<dependencyManagement></dependencyManagement>把項目A中主要jar包的版本鎖住,那麼其他依賴該項目的項目中,即便是有同名jar包直接依賴,也無法進行覆蓋了。

 

學習資料來源:https://www.bilibili.com/video/av70969191?p=30

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章