Maven使用總結
Maven使用總結
依賴範圍
-
maven建立的工程的目錄中包含
main
和test
資料夾,分別表示主程式的資料夾和測試程式的資料夾 -
maven使用
scop
設定依賴範圍,常用的依賴範圍如下:-
compile :編譯依賴範圍,在測試和執行都有效,這個是 預設 的依賴範圍
- 對主程式是否有效:有效
- 對測試程式是否 有效: 有效
- 是否參與打包:參與``
- 是否參與部署:參與
-
test:測試依賴的範圍
junit
-
provided
- 對主程式是否有效: 有效
- 對測試程式是否有效:有效
- 是否參與打包:不參與
- 是否參與部署:不參與
- 典型的例子:
servlet-api
- 主要解決在開發中需要用到的,但是在部署的時候不需要的依賴,比如
servlet-api
,在開發中沒有Tomcat執行環境,因此需要這個servlet-api
,但是一旦部署在Tomcat中,Tomcat中會提供這個servlet-api
,如果此時在新增的話會產生依賴衝突
- 主要解決在開發中需要用到的,但是在部署的時候不需要的依賴,比如
-
Runtime
:測試和執行時需要。編譯不需要。如JDBC驅動包- 對測試程式是否有效:有效
- 對主程式是否有效:有效
- 是否參與部署: 參與
- 是否參與打包:參與
-
system
:系統依賴範圍。本地依賴,不在maven中央倉庫- 這個必須和
systemPath
結合使用,用來指定本地依賴的位置
<!-- 新增服務提供者的jar介面 --> <dependency> <groupId>cn.tedu.dubbo</groupId> <artifactId>dubbo-provider</artifactId> <version>0.0.1</version> <scope>system</scope> <systemPath>${basedir}/src/main/webapp/WEB-INF/lib/dubbo-provider-helloService-0.0.1.jar</systemPath> </dependency>
- 這個必須和
-
依賴傳遞
- 在開發專案的時候,我們通常需要建立多個專案,如果一個專案中需要用到另外一個專案的類或者資料,那麼需要引入這個專案快照
- 如果
HelloFriend
專案 依賴Hello
這個專案,此時的HelloFriend
的pom.xml
檔案如下:
<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>cn.tedu</groupId> <artifactId>HelloFriend</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <!-- 新增Hello這個專案的依賴快照 --> <dependency> <groupId>cn.tedu</groupId> <artifactId>Hello</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> </project>
- 此時專案
HelloFriend
中存在依賴只有Hello
專案這個jar
,但是如果我們在Hello
專案的pom.xml
檔案中新增一個junit
的依賴,這個依賴範圍為設定為compile
,如下:
<dependencies> <!-- Junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>compile</scope> </dependency> </dependencies>
- 做了上面的操作,我們可以檢視專案
HelloFriend
和Hello
中都自動的匯入了Junit
依賴,這個就是依賴傳遞。
注意
- 依賴傳遞只有是依賴範圍為
compile
的情況下才有作用,如果我們需要一個servlet-api
的依賴,因為servlet-api
這個jar在部署的時候會和Tomcat衝突,因此只能設定為provided
,但是此時就不能依賴傳遞了,只能在每個專案中的pom.xml
檔案中都添加了
依賴排除
-
HelloFriend
專案依賴Hello
專案,其中compile
範圍的依賴都會匯入HelloFriend
中 - 使用
dubbo
預設會新增給我們新增spring-framework
的版本為2.5.6
,預設新增的依賴只能排除,不能在專案中再新增一個其他的版本,只有排除之後才能新增,否則會導致jar包衝突 -
Hello
專案中的依賴為:
<!-- Junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>compile</scope> </dependency> <!-- 新增dubbo依賴的jar,會自動新增spring 2.5版本的依賴 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.5.3</version> </dependency>
-
此時
HelloFriend
的專案需要使用4.3.13
版本的spring,那麼我們有如下解決辦法:- 在
Hello
專案中改變依賴,排除spring2.5版本的:- 一般在公司中專案的版本都是定製好的,我們不可能隨意改動父專案中定義好的版本,因此這個方法明顯是不行的
<!-- 使用spring4.3.13 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.13.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.5.3</version> <!--排除spring2.5版本--> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> </exclusions> </dependency>
- 在
- 我們可以在專案
HelloFriend
排除這個spring的依賴,那麼我們就可以不需要改變Hello
專案中的依賴了,如下:- 這個才是正確的排除依賴的方式
<!-- SpringMVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.13.RELEASE</version> </dependency> <!-- 新增Hello這個專案的依賴快照 --> <dependency> <groupId>cn.tedu</groupId> <artifactId>Hello</artifactId> <version>0.0.1-SNAPSHOT</version> <!--排除專案中的spring2.5的依賴,這個不會影響Hello專案中的版本--> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> </exclusions> </dependency>
依賴原則
依賴路徑最短優先原則
- 假設專案
MakeFriend
依賴HelloFriend
,並且HelloFriend
依賴Hello
專案。此時Hello專案中
使用的log4j 1.2.14
版本的,但是在HelloFriend
版本中使用的是log4j1.2.17
版本的,那麼此時的MakeFriend
應該選擇什麼版本呢? -
image
-
Hello
的依賴如下:
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.14</version> </dependency>
-
HelloFriend
依賴如下:
<!-- 新增Hello這個專案的依賴快照 --> <dependency> <groupId>cn.tedu</groupId> <artifactId>Hello</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!--新增1.2.17版本的log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
-
MakeFriend
的依賴如下:
<dependency> <groupId>cn.tedu</groupId> <artifactId>HelloFriend</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
- 我們根據圖形可以看到
MakeFriend
到HelloFriend
的log4j1.2.17
的路徑是2
,但是到Hello
中的log4j1.2.14
的路徑為3
,因此Maven會選擇HelloFriend
中的log4j1.2.17
版本作為MakeFriend的依賴
pom檔案中申明順序優先
-
在
路徑
都是一樣的情況下,那麼就要看在pom.xml
檔案中申明的順序了,先申明的就使用哪個專案中的依賴版本 -
假設現在的依賴改變了,
MakeFriend
現在是直接依賴Hello
和HelloFriend
,如下圖 -
image
-
我們可以看出此時到兩個版本的依賴都是一樣的路徑為
2
,那麼我們應該選擇哪個版本呢,此時就需要看看在MakeFriend
中的pom.xml
檔案的申明順序- 可以看出先申明的是
HelloFriend
,因此MakeFriend
使用的是log4j1.2.17
- 可以看出先申明的是
<!-- 先申明HelloFriend,那麼就要使用log4j.1.2.17版本 --> <dependency> <groupId>cn.tedu</groupId> <artifactId>HelloFriend</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>cn.tedu</groupId> <artifactId>Hello</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
覆寫優先
生命週期
- maven的生命週期有三個部分組成,分別為
clean生命週期
,site生命週期
,default生命週期
生命週期呼叫的特點
- 三大生命週期中也會包含各個階段,並且各個階段是有序進行的,maven為了實現構建的自動化,如果我們使用了命令呼叫生命週期後面的處理階段,那麼會從最前面的階段開始執行,不用每一個階段都執行一遍。
clean生命週期
-
在進行真正的構建之前進行一些清理工作
-
clean生命週期包括:
per-clean clean post-clean
-
當我們執行
mvn:clean
命令的時候只會執行per-clean
和clean
這兩個階段的任務,不會執行post-clean
的工作
default生命週期
- 構建的核心部分,編譯、測試、打包、部署
- 包括如下的23個生命週期階段:
生命週期階段 | 描述 |
---|---|
validate | 檢查工程配置是否正確,完成構建過程的所有必要資訊是否能夠獲取到。 |
initialize | 初始化構建狀態,例如設定屬性。 |
generate-sources | 生成編譯階段需要包含的任何原始碼檔案。 |
process-sources | 處理原始碼,例如,過濾任何值(filter any value)。 |
generate-resources | 生成工程包中需要包含的資原始檔。 |
process-resources | 拷貝和處理資原始檔到目的目錄中,為打包階段做準備。 |
compile | 編譯工程原始碼。 |
process-classes | 處理編譯生成的檔案,例如 Java Class 位元組碼的加強和優化。 |
generate-test-sources | 生成編譯階段需要包含的任何測試原始碼。 |
process-test-sources | 處理測試原始碼,例如,過濾任何值(filter any values)。 |
test-compile | 編譯測試原始碼到測試目的目錄。 |
process-test-classes | 處理測試程式碼檔案編譯後生成的檔案。 |
test | 使用適當的單元測試框架(例如JUnit)執行測試。 |
prepare-package | 在真正打包之前,為準備打包執行任何必要的操作。 |
package | 獲取編譯後的程式碼,並按照可釋出的格式進行打包,例如 JAR、WAR 或者 EAR 檔案。 |
pre-integration-test | 在整合測試執行之前,執行所需的操作。例如,設定所需的環境變數。 |
integration-test | 處理和部署必須的工程包到整合測試能夠執行的環境中。 |
post-integration-test | 在整合測試被執行後執行必要的操作。例如,清理環境。 |
verify | 執行檢查操作來驗證工程包是有效的,並滿足質量要求。 |
install | 安裝工程包到本地倉庫中,該倉庫可以作為本地其他工程的依賴。 |
deploy | 拷貝最終的工程包到遠端倉庫中,以共享給其他開發人員和工程。 |
mvn compile
Site生命週期
- Maven Site 外掛一般用來建立新的報告文件、部署站點等。
- 包含以下階段
pre-site site post-site site-deploy
Maven統一管理依賴的版本號
- 假設如下的依賴:
<!-- SpringMVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.13.RELEASE</version> </dependency> <!-- Spring-JDBC,要和spring-webmvc的版本一致 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.13.RELEASE</version> </dependency>
- 那麼當我們需要改變spring的依賴版本號為
4.3.12.RELEASE
,那麼我們只有逐個改變version
中的值,現在是兩個依賴比較好改變的,如果要有很多個的話,那麼難免會改錯,因此我們需要使用一種方式統一管理依賴的版本號。我們可以使用<properties>
標籤來管理,新的配置檔案如下:-
properties
中的標籤體可以任意指定,如果需要引用定義的標籤體中的內容,那麼直接使用${標籤體}
即可 - 此時我們要是改變版本,那麼只需要改變
<properties>
中的版本即可
-
<!-- 使用properties管理版本號 --> <properties> <!-- 這裡的標籤體可以任意指定,後續只要使用${}引用標籤體即可使用其中定義的內容 --> <spring-version>4.3.13.RELEASE</spring-version> </properties> <dependencies> <!-- SpringMVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <!-- version使用${} --> <version>${spring-version}</version> </dependency> <!-- Spring-JDBC,要和spring-webmvc的版本一致 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring-version}</version> </dependency> </dependencies>
繼承
- 我們知道只有
compile
範圍內的依賴才可以傳遞,但是對於test
和provided
中的依賴卻是不可以傳遞的,那麼必須在每個專案中都要新增依賴,此時肯定會出現每個專案中依賴版本不一致的情況,這樣對於每個人的開發來說是比較困難的,因為不同版本的依賴使用的方式也不同,此時我們就需要統一管理這個版本了。 - 下面我們以
junit
的版本控制為例
步驟
- 建立一個父工程
Hello-Parent
,打包的方式為pom
- 在
Hello-Parent
中的pom.xml
檔案中使用dependencyManagement
管理版本,控制junit
的版本依賴
<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>cn.tedu</groupId> <artifactId>Hello-Parent</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <!-- 使用properties控制版本號 --> <properties> <junit-version>4.12</junit-version> </properties> <!-- 使用dependencyManagement管理版本 --> <dependencyManagement> <dependencies> <!-- Junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit-version}</version> <scope>test</scope> </dependency> </dependencies> </dependencyManagement> </project>
- 在子工程中使用
parent
標籤指定宣告對父工程的引用
<parent> <groupId>cn.tedu</groupId> <artifactId>Hello-Parent</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- 使用relativePath指定父工程的相對位置 --> <relativePath>../Hello-Parent</relativePath> </parent>
- 將子工程座標和父工程座標重複的地方刪除,不刪除也沒關係
- 在子工程中刪除
junit
的version
標籤,表明是繼承自父工程的版本,不需要指定
<!-- Junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <!--此時不需要指定version了,因為父工程中已經指定了--> </dependency>
- 子工程全部的配置
<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和父工程中的重複了,因此可以刪除 <groupId>cn.tedu</groupId>--> <artifactId>Hello</artifactId> <!-- 這裡的version版本也和父工程的重複了,因此可以刪除 <version>0.0.1-SNAPSHOT</version> --> <parent> <groupId>cn.tedu</groupId> <artifactId>Hello-Parent</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- 使用relativePath指定父工程的相對位置 --> <relativePath>../Hello-Parent</relativePath> </parent> <dependencies> <!-- Junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <!--不需要指定version--> </dependency> </dependencies> </project>
聚合
- 我們在開發專案的時候都是分模組開發的,此時如果想要使用maven安裝這個專案的話,那麼需要一個一個的安裝,但是我們可以使用聚合的方式,可以實現一次性安裝。並且安裝還是有先後順序的,一定要先安裝父工程,否則將會找不到依賴資訊,我們使用聚合的方式就沒有先後安裝的障礙了,maven會為我們自動的解決
步驟
pom module
<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>cn.tedu</groupId> <artifactId>Hello-Manager</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <!-- 繼承父工程 --> <parent> <groupId>cn.tedu</groupId> <artifactId>Hello-Parent</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- 使用relativePath指定父工程的相對位置 --> <relativePath>../Hello-Parent</relativePath> </parent> <!-- 使用聚合的方式 --> <modules> <module>../Hello-Parent</module> <module>../Hello</module> <module>../HelloFriend</module> <module>../MakeFriend</module> </modules> </project>