Maven依賴機制

依賴傳遞

依賴相關命令

mvn dependency:list:查看當前項目全部依賴。
mvn dependency:tree:以樹的形式顯示當前項目的全部依賴,相比mvn dependency:list 列表顯示,能很清楚的看到某個依賴是經過哪條依賴路徑引入的。
mvn dependency:analyze:分析項目的依賴關係,並肯定哪些依賴是:使用和聲明、使用和未聲明、未使用和聲明。maven

依賴的傳遞性

若有依賴關係爲A->B->C,A依賴B,稱爲直接依賴。A自己不依賴C,但C經過B傳遞給A,稱C爲A的傳遞性依賴
ide

經過mvn dependency:list查看A項目的依賴列表,能夠看到依賴B和C:測試

[INFO] --- maven-dependency-plugin:2.8:list (default-cli) @ A --- 
    [INFO] 
    [INFO] The following files have been resolved:
    [INFO]    com.nocoffee:B:jar:0.0.1-SNAPSHOT:compile
    [INFO]    junit:junit:jar:3.8.1:test
    [INFO]    com.nocoffee:C:jar:0.0.1-SNAPSHOT:compile
    [INFO] 
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS 
    [INFO] ------------------------------------------------------------------------

依賴調解

場景1:

路徑1:A->B->C(version:1.0)
路徑2:A->D->E->C(version:2.0)
經過兩條依賴路徑能夠看出,A的傳遞性依賴的C有兩個不一樣版本,爲了不依賴重複,最終只能選擇一個。這種狀況Maven採用路徑最近者優先的原則來處理,路徑1中C到A的距離比路徑2中C到A的距離要短,因而路徑1中C(version:1.0)最終被A依賴。spa

mvn dependency:tree 查看依賴路徑:code

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ A ---
    [INFO] com.nocoffee:A:jar:0.0.1-SNAPSHOT
    [INFO] +- com.nocoffee:B:jar:0.0.1-SNAPSHOT:compile
    [INFO] |  \- com.nocoffee:C:jar:0.0.1-SNAPSHOT:compile
    [INFO] |     \- com.nocoffee:D:jar:0.0.1-SNAPSHOT:compile
    [INFO] |        \- com.nocoffee:E:jar:0.0.1-SNAPSHOT:compile
    [INFO] \- junit:junit:jar:3.8.1:test
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------

場景2:

路徑1:A->B->C(version:1.0)
路徑2:A->D->C(version:2.0)
路徑1和路徑2中C到A的距離是相同的,經過路徑最近者優先原則沒法判斷該使用哪一個依賴,此時Maven會使用第一聲明者優先原則進行選擇,第一聲明者優先原則是指在POM依賴中聲明順序最靠前的那個依賴會被選擇。在A的POM文件中B的聲明靠前,因而C(version:1.0)會被選擇。xml

<!-- A的pom.xml中依賴部分-->
    <dependencies>
    <dependency>
      <groupId>com.nocoffee</groupId>
      <artifactId>B</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <dependency>
      <groupId>com.nocoffee</groupId>
      <artifactId>D</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
    
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

mvn dependency:tree 查看依賴路徑:blog

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ A ---
    [INFO] com.nocoffee:A:jar:0.0.1-SNAPSHOT
    [INFO] +- com.nocoffee:B:jar:0.0.1-SNAPSHOT:compile
    [INFO] |  \- com.nocoffee:C:jar:0.0.1-SNAPSHOT:compile
    [INFO] +- com.nocoffee:D:jar:0.0.1-SNAPSHOT:compile
    [INFO] \- junit:junit:jar:3.8.1:test
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------

排除依賴

在場景2中,若是要使A依賴C(version:2.0) ,則能夠配置排除依賴:ip

<dependencies>
    <dependency>
      <groupId>com.nocoffee</groupId>
      <artifactId>B</artifactId>
      <version>0.0.1-SNAPSHOT</version>

      <exclusions>
        <!-- 排除依賴 C -->
        <exclusion>
            <groupId>com.nocoffee</groupId>
            <artifactId>C</artifactId>
        </exclusion>
      </exclusions>

    </dependency>
    <dependency>
      <groupId>com.nocoffee</groupId>
      <artifactId>D</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
    
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

mvn dependency:tree 查看依賴路徑,A再也不經過B依賴C,而是經過D依賴C:ci

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ A ---
    [INFO] com.nocoffee:A:jar:0.0.1-SNAPSHOT
    [INFO] +- com.nocoffee:B:jar:0.0.1-SNAPSHOT:compile
    [INFO] +- com.nocoffee:D:jar:0.0.1-SNAPSHOT:compile
    [INFO] |  \- com.nocoffee:C:jar:0.0.1-SNAPSHOT:compile
    [INFO] \- junit:junit:jar:3.8.1:test
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------

可選依賴

能夠將某個依賴配置爲可選依賴,則該依賴不會參與依賴傳遞。

以場景2爲例,能夠在B的pom.xml裏將C配置爲可選依賴,使A依賴D的C(version:2.0)。it

<!-- B的pom.xml -->
    <dependency>
      <groupId>com.nocoffee</groupId>
      <artifactId>C</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <!-- 設置可選依賴 -->
      <optional>true</optional>
    </dependency>

mvn dependency:tree 查看依賴路徑,A再也不經過B依賴C,而是經過D依賴C:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ A ---
    [INFO] com.nocoffee:A:jar:0.0.1-SNAPSHOT
    [INFO] +- com.nocoffee:B:jar:0.0.1-SNAPSHOT:compile
    [INFO] +- com.nocoffee:D:jar:0.0.1-SNAPSHOT:compile
    [INFO] |  \- com.nocoffee:C:jar:0.0.1-SNAPSHOT:compile
    [INFO] \- junit:junit:jar:3.8.1:test
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------

依賴範圍

Maven在編譯、測試、運行時都會使用不一樣的classpath,依賴範圍是用來控制依賴和三種classpath的關係。

依賴範圍介紹

  1. compile:編譯依賴範圍,默認使用該依賴範圍,在全部classpath中均可用,而且依賴項將傳播到依賴項目。
  2. provided:已提供依賴範圍,只對於編譯和測試classpath有效,運行時無效,如Servlet API,此範圍不具備傳遞性。
  3. runtime:運行時依賴範圍,只對於測試和運行classpath有效,但在編譯主代碼時無效。
  4. test:測試依賴範圍,只對於測試的classpath有效,僅適用於測試編譯和執行階段,如junit。此範圍不具備傳遞性。
  5. system:系統依賴範圍,該依賴於三種classpath的關係和provided依賴範圍徹底一致。區別在於system依賴範圍必須經過systemPath元素顯示的指定依賴文件的路徑。
  6. import:導入依賴範圍,該依賴範圍不會對三種classpath產生影響,只有在 部分中的pom類型依賴項才支持此範圍,它指示要替換爲指定POM的 部分中的有效依賴項列表的依賴項。因爲它們被替換,具備導入範圍的依賴項實際上不參與限制依賴項的傳遞性。

依賴範圍對依賴傳遞的影響

每一個範圍(import導入依賴範圍除外)以不一樣方式影響傳遞依賴性,以下表所示。以A->B->C依賴路徑爲例,左邊第一列爲第一直接依賴(B在A中的依賴範圍),最上面一行爲第二直接依賴(C在B中的依賴範圍),交叉單元格爲傳遞性依賴範圍(C在A中的依賴範圍)。

compile provided runtime test
compile compile(*) - runtime -
provided provided - provided -
runtime runtime - runtime -
test test - test -
相關文章
相關標籤/搜索