這段時間項目中遇到過了一些 Jar 包衝突的問題,不少是因爲咱們項目模塊不少的時候,用 Maven 管理不當致使的衝突問題,本文就這個問題參考網上的資料,因而總結下 Maven 中 dependencies 與 dependencyManagement 的區別。java
假設項目結構以下:apache
parent 爲父模塊,抽象出來管理子項目的公共依賴,爲了項目的正確運行,必須讓全部的子項目使用依賴項的統一版本,必須確保應用的各個項目的依賴項和版本一致,才能保證測試的和發佈的是相同的結果。api
在項目的 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,以更細化的方式管理依賴。這種作法與面向對象設計中使用組合而非繼承也有點類似的味道。插件
相對於 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