Maven 中 dependencies 與 dependencyManagement 的區別

Maven 中 dependencies 與 dependencyManagement 的區別

 

前提

這段時間項目中遇到過了一些 Jar 包衝突的問題,不少是因爲咱們項目模塊不少的時候,用 Maven 管理不當致使的衝突問題,本文就這個問題參考網上的資料,因而總結下 Maven 中 dependencies 與 dependencyManagement 的區別。java

假設項目結構以下:apache

 

 

parent 爲父模塊,抽象出來管理子項目的公共依賴,爲了項目的正確運行,必須讓全部的子項目使用依賴項的統一版本,必須確保應用的各個項目的依賴項和版本一致,才能保證測試的和發佈的是相同的結果。api

dependencyManagement

在項目的 parent 層,能夠經過 dependencyManagement 元素來管理 jar 包的版本,讓子項目中引用一個依賴而不用顯示的列出版本號。maven

parent 中 pom.xml單元測試

<properties>
    <version.framework>1.0-SNAPSHOT</version.framework>
    <javaee-api.version>1.0-SNAPSHOT</javaee-api.version>
</properties>
<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.zhisheng</groupId>
        <artifactId>framework-cache</artifactId>
        <version>${version.framework}</version>
      </dependency>
      <dependency>  
        <groupId>javax</groupId>  
        <artifactId>javaee-api</artifactId>  
        <version>${javaee-api.version}</version>  
      </dependency>  
    </dependencies>
</dependencyManagement>

 

extendion 中的 pom.xml測試

<parent>  
    <artifactId>parent</artifactId>  
    <groupId>com.zhisheng</groupId>
    <version>0.0.1-SNAPSHOT</version>  
	<relativePath>../parent/pom.xml</relativePath> 
</parent>
<!--依賴關係-->  
<dependencies>  
    <dependency>  
        <groupId>javax</groupId>  
        <artifactId>javaee-api</artifactId>  
    </dependency>  
    <dependency>
        <groupId>com.zhisheng</groupId>
        <artifactId>framework-cache</artifactId>
    </dependency>
    <dependency>  
        <groupId>com.fasterxml.jackson.core</groupId>  
        <artifactId>jackson-annotations</artifactId>  
    </dependency>  
</dependencies>

 

這樣作的好處:統一管理項目的版本號,確保應用的各個項目的依賴和版本一致,才能保證測試的和發佈的是相同的成果,所以,在頂層 pom 中定義共同的依賴關係。同時能夠避免在每一個使用的子項目中都聲明一個版本號,這樣想升級或者切換到另外一個版本時,只須要在父類容器裏更新,不須要任何一個子項目的修改;若是某個子項目須要另一個版本號時,只須要在 dependencies 中聲明一個版本號便可。子類就會使用子類聲明的版本號,不繼承於父類版本號。ui

咱們知道 Maven 的繼承和 Java 的繼承同樣,是沒法實現多重繼承的,若是10個、20個甚至更多模塊繼承自同一個模塊,那麼按照咱們以前的作法,這個父模塊的 dependencyManagement 會包含大量的依賴。若是你想把這些依賴分類以更清晰的管理,那就不可能了,import scope 依賴能解決這個問題。你能夠把 dependencyManagement 放到單獨的專門用來管理依賴的 POM 中,而後在須要使用依賴的模塊中經過 import scope 依賴,就能夠引入dependencyManagement。例如能夠寫這樣一個用於依賴管理的 POM:編碼

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.zhisheng.sample</groupId>
  <artifactId>sample-dependency-infrastructure</artifactId>
  <packaging>pom</packaging>
  <version>1.0-SNAPSHOT</version>
  <dependencyManagement>
    <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactid>junit</artifactId>
          <version>4.8.2</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>log4j</groupId>
          <artifactid>log4j</artifactId>
          <version>1.2.16</version>
        </dependency>
    </dependencies>
  </dependencyManagement>
</project>

 

而後就能夠經過非繼承的方式來引入這段依賴管理配置:spa

<dependencyManagement>
    <dependencies>
        <dependency>
          <groupId>com.zhisheng.sample</groupId>
          <artifactid>sample-dependency-infrastructure</artifactId>
          <version>1.0-SNAPSHOT</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
    </dependencies>
  </dependencyManagement>
  <dependency>
    <groupId>junit</groupId>
    <artifactid>junit</artifactId>
  </dependency>
  <dependency>
    <groupId>log4j</groupId>
    <artifactid>log4j</artifactId>
  </dependency>

 

這樣,父模塊的 POM 就會很是乾淨,由專門的 packaging 爲 pom 的 POM 來管理依賴,也契合的面向對象設計中的單一職責原則。此外,咱們還可以建立多個這樣的依賴管理 POM,以更細化的方式管理依賴。這種作法與面向對象設計中使用組合而非繼承也有點類似的味道。插件

dependencies

相對於 dependencyManagement,全部聲明在父項目中 dependencies 裏的依賴都會被子項目自動引入,並默認被全部的子項目繼承。

區別

dependencies 即便在子項目中不寫該依賴項,那麼子項目仍然會從父項目中繼承該依賴項(所有繼承)

dependencyManagement 裏只是聲明依賴,並不實現引入,所以子項目須要顯示的聲明須要用的依賴。若是不在子項目中聲明依賴,是不會從父項目中繼承下來的;只有在子項目中寫了該依賴項,而且沒有指定具體版本,纔會從父項目中繼承該項,而且 version 和 scope 都讀取自父 pom; 另外若是子項目中指定了版本號,那麼會使用子項目中指定的jar版本。

消除多模塊插件配置重複

與 dependencyManagement 相似的,咱們也可使用 pluginManagement 元素管理插件。一個常見的用法就是咱們但願項目全部模塊的使用 Maven Compiler Plugin 的時候,都使用 Java 1.8,以及指定 Java 源文件編碼爲 UTF-8,這時能夠在父模塊的 POM 中以下配置 pluginManagement:

<build>
  <pluginManagement>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.5.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
    </plugins>
  </pluginManagement>
</build>

 

這段配置會被應用到全部子模塊的 maven-compiler-plugin 中,因爲 Maven 內置了 maven-compiler-plugin 與生命週期的綁定,所以子模塊就再也不須要任何 maven-compiler-plugin 的配置了。

與依賴配置不一樣的是,一般全部項目對於任意一個依賴的配置都應該是統一的,但插件卻不是這樣,例如你能夠但願模塊 A 運行全部單元測試,模塊 B 要跳過一些測試,這時就須要配置 maven-surefire-plugin 來實現,那樣兩個模塊的插件配置就不一致了。這也就是說,簡單的把插件配置提取到父 POM 的 pluginManagement 中每每不適合全部狀況,那咱們在使用的時候就須要注意了,只有那些普適的插件配置才應該使用 pluginManagement 提取到父 POM 中。

關於插件 pluginManagement,Maven 並無提供與 import scope 依賴相似的方式管理,那咱們只能藉助繼承關係,不過好在通常來講插件配置的數量遠沒有依賴配置那麼多,所以這也不是一個問題。

轉載自:https://zhuanlan.zhihu.com/p/31020263

相關文章
相關標籤/搜索