說說maven依賴衝突,依賴調解,依賴傳遞和依賴範圍

說maven依賴衝突以前須要先說說maven的 依賴傳遞java

依賴傳遞

當前項目引入了一個依賴,該依賴的依賴也會被引入項目。更加準確的說法是,maven會解析直接依賴的POM,將那些必要的間接依賴,以傳遞依賴的形式引入到當前項目中。spring

爲何說是’必要的間接依賴‘呢?這是由於不是全部的間接依賴都會被引入的。這還得說說maven的 依賴範圍apache

依賴範圍

maven引入依賴,並非把jar包拷貝到項目中來,而是把jar包下載到本地倉庫,而後經過制定classpath來在項目中引入具體的jar包。maven管理着3套classpath,分別是 編譯classpath測試classpath運行classpathapi

依賴範圍就是用來控制着3個classpath的,maven的依賴範圍有:maven

  • compile: 編譯依賴範圍。對所有classpath都有效。例子:spring-core
  • test: 測試依賴範圍。只對測試classpath有效。例子:junit
  • provided: 已提供依賴範圍。對編譯和測試classpath有效。例子:servlet-api
  • runtime: 運行時依賴範圍。對測試和運行classpath有效。例子:JDBC驅動
  • system: 系統依賴範圍。對編譯和測試classpath有效。經過systemPath顯式指定。
  • import: 導入依賴範圍。不會對classpath產生影響。

依賴範圍除了控制classpath,還會對依賴傳遞產生影響。若是A依賴B,B依賴C,則A對於B是第一直接依賴。B對於C是第二直接依賴。A對於C是傳遞性依賴。結論是:第一直接依賴的範圍和第二直接依賴的範圍決定了傳遞性依賴的範圍。ide

用《Maven實戰》上的表格來講明:測試

第一直接依賴第二直接依賴
compile
test provided runtime
compile
compile
-
-
runtime
test
test
-
-
test
provided
provided -
provided provided
runtime
runtime
-
-
runtime

第一列是第一直接依賴,第一行是第二直接依賴,中間表示傳遞性依賴範圍。ui

依賴衝突和依賴調解

真是由於依賴傳遞,因此才帶來了依賴衝突的可能。好比A->X(1.0),A->B->X(2.0)。A直接依賴了1.0版本的X,而A依賴的B依賴了2.0版本的X。若是依賴範圍合適的話,B中依賴的X也是會傳遞到A項目中的。而兩個X的版本不一致,這就產生了依賴衝突。spa

在依賴衝突發生時,maven不會直接提示錯誤,而是用一套規則來進行 依賴調解。規則有兩條:.net

  1. 路徑最近者優先。
  2. 第一聲明者優先。

依賴路徑指的是項目到依賴的長度,好比A->X(1.0)長度爲1,A->B->X(2.0)長度爲2,因此最終會使用1.0版本的X。

若是二者的路徑同樣呢?好比A->B->X(2.0)和A->C->X(3.0),這兩個依賴路徑的長度都是2,那用哪一個呢?這就須要第二個規則了,也就是哪一個先聲明就用哪一個。

大部分狀況下maven這種自動的依賴調解能幫咱們解決問題了。可是有時候咱們不得不手動處理依賴衝突。這種衝突可能不是同一個依賴的不一樣版本(這個依賴調解能搞定),而是不能同時出現的兩個依賴。好比slf4j-log4j和logback這兩個依賴是不能同時出現的,可是由於他們的座標不同,因此maven不會對齊進行處理。這個時候咱們就須要手動進行 排除依賴 了。

排除依賴

下面的例子就是排除依賴的例子,排除依賴的時候就不用指定版本了:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.5.3</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring</artifactId>
        </exclusion>
    </exclusions>
</dependency>複製代碼

這種排除是很方便來了,若是有許多相同的間接依賴須要排除的話,會比較麻煩,能夠參考:maven實現依賴的「全局排除」

檢查依賴衝突

由於maven在依賴衝突發生時使用依賴調解,因此不會有任何提示。那咱們要如何檢查呢?方法有兩種。

第一種是使用mvn dependency:tree -Dverbose來列出項目的全部依賴以及傳遞性依賴。對於重複和衝突的依賴,會提示omitted for duplicateomitted for conflict with x.x.x

第二個方法是使用maven的enforcer插件。在項目POM中加入:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>1.4.1</version>
            <executions>
                <execution>
                    <id>enforce</id>
                    <configuration>
                        <rules>
                            <dependencyConvergence/>
                        </rules>
                    </configuration>
                    <goals>
                        <goal>enforce</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>複製代碼

這樣在用maven編譯時,若是存在依賴衝突,就會有錯誤提示:

[ERROR]
Dependency convergence error for org.slf4j:slf4j-api:1.6.1 paths to dependency are:
+-org.myorg:my-project:1.0.0-SNAPSHOT
  +-org.slf4j:slf4j-jdk14:1.6.1
    +-org.slf4j:slf4j-api:1.6.1
and
+-org.myorg:my-project:1.0.0-SNAPSHOT
  +-org.slf4j:slf4j-nop:1.6.0
    +-org.slf4j:slf4j-api:1.6.0複製代碼

參考資料

本文獨立博客地址:說說maven依賴衝突,依賴調解,依賴傳遞和依賴範圍 | 木杉的博客

相關文章
相關標籤/搜索