上一篇博文講到如何安裝maven,這篇算是它的續篇,總結下maven是如何管理依賴的。
maven強大之處就是管理依賴。通過依賴傳遞,依賴繼承,以及pom匯入,可以輕鬆實現依賴的版本管理。通過依賴scope實現在不同的生命週期時段,加入依賴。
如下是一個最簡單的為當前項目添加依賴的樣本:
IntelliJ Idea > Preferences… > Build, Execution, Deployment > Build Tools > Maven
Importing一欄,將”Import Maven projects automatically” 勾選上。如果這一欄沒有勾選的話,Idea會在右上方有個漂浮提示,也可以從這個提示那裡點擊開啟。
接下來,往pom.xml裡添加一條依賴,IDE會自動將此依賴添加到External Libraries裡面。
<dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency>
#### 依賴傳遞 ####
比如我在pom.xml裡加上了junit. 而junit要依賴於hamcrest-core。但是我不用再添加對於hamcrest-core的依賴,maven會自動做掉,於是我的External Libraries裡面不僅有junit,還有hamcrest-core.
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
#### 依賴scope #### compile: 預設的scope,如果在dependency節點裡沒有寫scope,那麼它預設是compile provided: JDK/容器在運行時會產生/提供這個依賴 runtime: 依賴僅在運行時需要,在編譯時間是不需要的 test: 依賴僅用於測試,並不用於真正的appliation,比如添加junit依賴時,就可以為它加上scope = test,前提是application本身真的不需要用到junit system: 貌似已經棄用了… import: 匯入別的pom的dependencyManagement部分
#### 依賴繼承 ####
依賴繼承有兩個重要作用: 將子項目的公用依賴加入到父項目裡,化簡子項目的pom.xml 通過父項目的dependencyManagement裡申明的版本號碼來管理所用依賴的版本
如下例子來自maven官方文檔。Project A是父項目。Project B是A的子項目,所以B繼承了A申明在dependencyManagement段落裡的依賴,即:a-1.2,b-1.0,c-1.0,d-1.2。
但是由於B自己本身有定義對於a和c的依賴,所以對於依賴a, B會用自己本身定義的a-1.0。對於依賴c,B裡面並未定義版本,所以maven會上溯至父親A中找到對c的版本定義,所以是c-1.0。對於依賴b,它沒有定義在B自己的pom裡,所以繼承自父親A,b-1.0。對於依賴d,父親A裡有,自己的dependencyManagement也有,優先選用自己的,所以是c-1.0。
<parent> <artifactId>A</artifactId> <groupId>maven</groupId> <version>1.0</version> </parent>
Project A的pom.xml:
<project> <modelVersion>4.0.0</modelVersion> <groupId>maven</groupId> <artifactId>A</artifactId> <packaging>pom</packaging> <name>A</name> <version>1.0</version> <dependencyManagement> <dependencies> <dependency> <groupId>test</groupId> <artifactId>a</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>test</groupId> <artifactId>b</artifactId> <version>1.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>test</groupId> <artifactId>c</artifactId> <version>1.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>test</groupId> <artifactId>d</artifactId> <version>1.2</version> </dependency> </dependencies> </dependencyManagement></project>
Project B的pom.xml:
<project> <parent> <artifactId>A</artifactId> <groupId>maven</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>maven</groupId> <artifactId>B</artifactId> <packaging>pom</packaging> <name>B</name> <version>1.0</version> <dependencyManagement> <dependencies> <dependency> <groupId>test</groupId> <artifactId>d</artifactId> <version>1.0</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>test</groupId> <artifactId>a</artifactId> <version>1.0</version> <scope>runtime</scope> </dependency> <dependency> <groupId>test</groupId> <artifactId>c</artifactId> <scope>runtime</scope> </dependency> </dependencies></project>
一般來說,將dependencyManagement置於頂層項目的pom.xml文檔中,用於依賴包的版本控制,以確保各個子項目中用到的依賴都是相同的版本。dependencyManagement僅申明依賴和版本,並不實際下載依賴包。
當子項目中的dependencies裡有申明某依賴且沒有版本號碼時,maven會上溯,直到在上層pom裡找到該依賴的版本。子項目不用顯示地寫依賴的版本,以達到統一管理依賴版本的目的。
如果想要將依賴傳遞下去(傳給子項目,或者傳給那些import 這個pom的項目),則把依賴定義在dependencyManagement部分。如果不想用父親/import進來的pom裡定義的依賴版本,則在dependency部分申明特定版本號碼的依賴。否則,就應該在dependency部分僅申明依賴,不申明依賴版本,統一用父親/import進來的pom裡定義的依賴版本,來實現版本管理。
#### 依賴匯入 ####
在大型項目中,依賴匯入使用的更多。這裡用依賴匯入來實現剛剛在依賴繼承小節實現的B繼承A的目的。
在B的pom.xml的dependencyManagement部分,import A的pom:
<project> <modelVersion>4.0.0</modelVersion> <groupId>maven</groupId> <artifactId>B</artifactId> <packaging>pom</packaging> <name>B</name> <version>1.0</version> <dependencyManagement> <dependencies> <dependency> <groupId>maven</groupId> <artifactId>A</artifactId> <version>1.0</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>test</groupId> <artifactId>d</artifactId> <version>1.0</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>test</groupId> <artifactId>a</artifactId> <version>1.0</version> <scope>runtime</scope> </dependency> <dependency> <groupId>test</groupId> <artifactId>c</artifactId> <scope>runtime</scope> </dependency> </dependencies></project>
在大型項目中,某些模組依賴某些項目是非常常見的,為了使這些模組的依賴項目版本統一,使用依賴繼承+依賴匯入是一種非常好的實踐。在根pom中指明依賴版本,在模組中匯入根pom,統一使用根pom定義的版本。將來依賴版本有更新時,只用更改根pom裡的版本號碼即可。這一點頗有設計模式的味道…
首先在根pom–bom(bill of material)的dependencyManagement部分申明依賴project1和project2,版本的話則引用properties部分定義的變數。並且根pom裡指明子項目parent。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test</groupId> <artifactId>bom</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <properties> <project1Version>1.0.0</project1Version> <project2Version>1.0.0</project2Version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>com.test</groupId> <artifactId>project1</artifactId> <version>${project1Version}</version> </dependency> <dependency> <groupId>com.test</groupId> <artifactId>project2</artifactId> <version>${project1Version}</version> </dependency> </dependencies> </dependencyManagement> <modules> <module>parent</module> </modules></project>
接下來在parent項目的pom-dependencyManagement部分,定義了一些外部依賴,並指定了版本。而且還定義了子項目project1和project2.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.test</groupId> <version>1.0.0</version> <artifactId>bom</artifactId> </parent> <groupId>com.test</groupId> <artifactId>parent</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <dependencyManagement> <dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> </dependencies> </dependencyManagement> <modules> <module>project1</module> <module>project2</module> </modules></project>
接下來是project1和project2的pom,它們的pom裡只申明了dependency而並未申明版本,因為要統一用父親parent pom裡定義的依賴版本。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.test</groupId> <version>1.0.0</version> <artifactId>parent</artifactId> </parent> <groupId>com.test</groupId> <artifactId>project1</artifactId> <version>${project1Version}</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </dependency> </dependencies></project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.test</groupId> <version>1.0.0</version> <artifactId>parent</artifactId> </parent> <groupId>com.test</groupId> <artifactId>project2</artifactId> <version>${project2Version}</version> <packaging>jar</