06.maven依賴管理


maven依賴管理

maven依賴說明

Maven的依賴管理十分強大,單個項目的依賴管理非常簡單,但是,當應用由多個模塊組成,並且應用有數十到數百個模塊組成時,依賴管理變得非常困難。此時,maven可以保證高度的依賴控制和穩定

maven的項目依賴主要配置在項目pom.xml的dependencies節點中。依賴是使用Maven座標來定位的,因此,使用任何一個依賴之間,你都需要知道它的Maven座標。

在maven組件搜索網站上,每個組件都有maven依賴的配置內容,只需要將內容複製到項目pom.xml中的dependencies節點即可。

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

完整的依賴節點包含以下節點:

  • groupId,必選,實際隸屬項目

  • artifactId,必選,其中的模塊

  • version必選,版本號

  • type可選,依賴類型,默認jar

  • scope可選,依賴作用域,默認compile

  • optional可選,標記依賴是否可選,默認false

  • exclusion可選,排除傳遞依賴性,默認空

上面的示例是編寫文檔時,junit的maven依賴。

依賴傳遞

依賴傳遞是maven2.0的新特徵。用於避免手動發現和添加需要的組件的依賴組件,maven會自動添加。

這個新特殊通過從遠程倉庫讀取項目依賴的工程文件實現,一般而言,組件的傳遞性依賴包括繼承自父項目的依賴組件,以及組件依賴的組件,等等。

因爲沒有限制依賴關係的層次。所以會產生一個問題:循環依賴(後面會有解決辦法)

因爲依賴傳遞,包含庫可能會快速增長,出於這個原因,一些特徵將用於限制依賴關係。

  • 依賴調解

當遇到一個組件的多個版本依賴時,通過依賴調解決定使用哪個版本的組件。 maven2.0只支持“就近原則”,即選擇離依賴樹中最近一個版本。當然,你也可以選擇顯示的在項目pom文件中指定一個版本。 在maven2.0.9版本及之後的版本中,如果兩個版本的組件在項目依賴樹的在同一深度,那麼哪個依賴先聲明,用哪個版本。

舉例說明:

wKiom1c0NVazlXwfAAAgXzI0zic719.png

在項目A中,依賴B與C組件,B組件依賴D1.0與E1.0,而組件C依賴於F與E2.0,F依賴與D2.0。此時,產生了依賴衝突,即對組件D和組件E的依賴。此時,因爲組件D1.0更靠近項目,所以使用組件D1.0,對於E組件,因爲距離項目的距離相同,所以POM中組件B與C在誰先聲明,就用誰的依賴版本。

如果在POM中顯示的聲明D與E的版本,則使用指定版本。

  • 依賴管理

即允許開發者在遇到傳遞性依賴,直接指定組件版本。

  • 依賴作用域

見下節

  • 依賴排除

假設X組件依賴於Y組件,Y組件依賴於Z組件,在引用X時,可以使用exclusion節點,排隊項目對Z組件的引用。這常常用於解除依賴調解的“就近原則” ,使用離項目較遠的版本。

  • 可選依賴

假設組件Y依賴於組件Z,在組件Y中可以通過optional節點將Z定義爲可選依賴。X引用Y組件依賴時,Z組件將不參與依賴傳遞。X組件可以選擇性的顯示引用Z組件。

maven依賴作用域

scope節點表示依賴作用域。

依賴作用域是用來限制依賴關係的傳遞性,同時影響各類組件的作用域。

maven依賴有以下幾種:

  • compile

此作用域這是默認的作用域,如果依賴沒的指定作用域,則使用此作用域。此依賴作用域的依賴可用於項目的所有類路徑。此外,此依賴作用域參與依賴傳遞。

  • provided

此作用域和compile很像,只是在運行時此依賴由JDK或者容器提供。舉個例子,當構建一個J2EE web應用時,你就要將Servlet API和Java EE API的依賴作用域設置爲provided,因爲容器提供了這些類。此依賴作用域只作用於編譯和測試的類路徑。不參與依賴傳遞

  • runtime

此作用域表示依賴在編譯時不需要,但是執行時需要,作用於運行和測試時,但是不在編譯的類路徑中。

  • test

此作用域表示依賴在項目一般使用中不需要,只在測試編譯和測試執行期間使用。

  • system

此作用域與provided作用域相似,只是你必須提供顯示包含的jar。組件必須可用,maven不會在repository裏查找組件。

  • import(只在Maven 2.0.9及以後的版本中可用)

此作用域只用於pom依賴,主要是用來導入另一個POM中 dependency management 裏聲明的依賴仲裁。

每個不同的作用域以不同的方式影響依賴傳遞。如下表所示: 如果一個項目依賴設置爲左列的作用域,本依賴的傳遞依賴的作用域爲第一行的值,那麼傳遞依賴作用於本項目的的作用域將取交叉單元格的值,未列出的作用域,將被忽略


compileprovidedruntimetest
compilecompile(*)-runtime-
providedprovided-provided-
runtimeruntime-runtime-
testtest-test-

system作用域

system作用域的依賴組件應該總是可用,maven用不會去倉庫中查找,system作用域通常用於告訴 maven 由JDK與虛擬機提供的依賴。如果你將一個依賴範圍設置成系統範圍,你必須同時提供一個 systemPath 元素。注意該範圍是不推薦使用的

經典的使用例子就是JDBC標準擴展,Java身份驗證和授權服務(JAAS)。

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>javax.sql</groupId>
      <artifactId>jdbc-stdext</artifactId>
      <version>2.0</version>
      <scope>system</scope>
      <systemPath>${java.home}/lib/rt.jar</systemPath>
    </dependency>
  </dependencies>
  ...
</project>

如果你的組件由JDK的tools.jar提供,系統路徑應如下定義:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>sun.jdk</groupId>
      <artifactId>tools</artifactId>
      <version>1.5.0</version>
      <scope>system</scope>
      <systemPath>${java.home}/../lib/tools.jar</systemPath>
    </dependency>
  </dependencies>
  ...
</project>

可選依賴

使用可選依賴的場景:一個項目A依賴於B,但是引用A的項目可能並不需要B,此時,A項目對B項目的依賴就可以配置成可選依賴,如果引用A的項目需要使用B的功能,可以手動引用B的依賴。

爲什麼使用可選依賴? 1. 節約磁盤、內存等空間; 1. 避免license許可問題; 1. 避免類路徑問題,等等。

<project>
  ...
  <dependencies>
    <!-- declare the dependency to be set as optional -->
    <dependency>
      <groupId>sample.ProjectA</groupId>
      <artifactId>Project-A</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
      <optional>true</optional> <!-- value will be true or false only -->
    </dependency>
  </dependencies>
</project>

配置可靠依賴只需要在dependency節點中添加true即可。

依賴排除

依賴排除的使用場景:當一個項目A依賴項目B,而項目B同時依賴項目C,如果項目A中因爲各種原因不想引用項目C,在配置項目B的依賴時,可以排除對C的依賴。

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>sample.ProjectA</groupId>
      <artifactId>Project-A</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
      <exclusions>
        <exclusion>  <!-- declare the exclusion here -->
          <groupId>sample.ProjectB</groupId>
          <artifactId>Project-B</artifactId>
        </exclusion>
      </exclusions> 
    </dependency>
  </dependencies>
</project>

配置依賴排除時,只需要在節點dependency添加exclusions節點,在exclusions節點中添加一個或者多個exclusion即可。exclusion節點包含groupIdartifactId節點,用於定義排隊的組件。

多重依賴

Demo:

對於如下依賴結構:

Project-A
   -> Project-B
        -> Project-D 
              -> Project-E
              -> Project-F
   -> Project C

A對於E相當於有多重依賴,如果想在項目A中排除對E的依賴,只需要在配置B的依賴中進行即可:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>sample.ProjectA</groupId>
  <artifactId>Project-A</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  ...
  <dependencies>
    <dependency>
      <groupId>sample.ProjectB</groupId>
      <artifactId>Project-B</artifactId>
      <version>1.0-SNAPSHOT</version>
      <exclusions>
        <exclusion>
          <groupId>sample.ProjectE</groupId> <!-- Exclude Project-E from Project-B -->
          <artifactId>Project-E</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>
</project>

maven處理循環依賴

循環依賴

如果工程A依賴工程B,工程B又依賴工程A,就會形成循環依賴。或者A依賴B,B依賴C,C依賴A,也是循環依賴,總的來說,在畫出工程依賴圖之後,如果發現工程間的依賴連線形成了一個有向循環圖,則說明有循環依賴的現象。

解決循環依賴

第一個辦法是用build-helper-maven-plugin插件來規避。比如A依賴B,B依賴C,C依賴A的情況。這個插件提供了一種規避措施,即臨時地將工程A、B、C合併成一箇中間工程,編譯出臨時的模塊D。然後A、B、C再分別依賴臨時模塊D進行編譯

第二個辦法是通過重構

重構的思路

第一個思路是平移重構,例如項目A和B互相依賴,那麼可以將B依賴A的那部分平移到工程B中,或者將A依賴B的部分平移到A項目中,這樣就能消除循環依賴。    第二個思路應對如下情況,比如A和B互相依賴,同時它們都依賴C,那麼可以將B和A相互依賴的那部分移動到工程C裏,這樣一來,A和B相互之間都不依賴,只繼續依賴C,也可以消除循環依賴。


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