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.RELEASE的spring-beans和5.2.4.RELEASE的spring-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-context和spring-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包直接依賴,也無法進行覆蓋了。