1 簡介
Maven是Apache軟件基金會唯一維護的一款自動化構建工具,專注於服務Java平臺的項目構建和依賴管理。
Maven是基於項目對象模型(POM),可以通過一小段描述信息來管理項目的構建、報告和文檔的軟件項目管理工具。
在有多個開發團隊環境的情況下,Maven 能夠在很短的時間內使得每項工作都按照標準進行。因爲大部分的工程配置操作都非常簡單並且可複用,在創建報告、檢查、構建和測試自動配置時,Maven 可以讓開發者的工作變得更簡單。
2 完成工作
- 構建項目(打包,編譯等)
- 文檔生成
- 報告
- 依賴(jar包之間的依賴關係)
- SCMs
- 發佈
- 分發
- 添加第三方jar包
- 郵件列表
3 工作原理
4 常用命令
mvn -version/-v —— 顯示版本信息
mvn clean —— 清空生成的文件
mvn compile —— 編譯
mvn test —— 編譯並測試
mvn package —— 生成target目錄,編譯、測試代碼,生成測試報告,生成jar/war文件
mvn site —— 生成項目相關信息的網站
mvn clean compile —— 表示先運行清理之後運行編譯,會將代碼編譯到target文件夾中
mvn clean package —— 運行清理和打包
mvn clean install —— 運行清理和安裝,會將打好的包安裝到本地倉庫中,以便其他的項目可以調用
mvn clean deploy —— 運行清理和發佈
5 核心概念
概念 | 說明 |
---|---|
LifeCycle | 生命週期,maven內置default,sie,clean三個生命週期 |
Phase | 階段,每個生命週期有不同的階段 |
Plugin | 插件,實現實際的構建功能 |
Goal | 一個插件可以實現多個goal,goal具備具體的功能 |
Execution | 通過配置,決定在某個Phase執行哪些Goal |
Project | maven管理的目標:軟件工程,小的工程可以聚合成大工程 |
PackageType | 爲了便於管理工程,按照構建目標區分成不同的工程類型,如jar,war,ear等 |
Dependency | 依賴,project之間存在依賴關係 |
DependencyScope | maven對依賴定義了不同的作用範圍 |
Management | 可以配置一個工程如何管理依賴關係 |
Repository | 倉庫,存放包,分爲本地庫和遠程庫 |
Build | 構建的動作。使用maven管理工程,主要是指定將project構建到某個phase |
6 幾種常見核心概念介紹
6.1 Maven約定的工程目錄
Java開發領域普遍認同的一個觀點:約定>配置>編碼(能用配置解決的問題就不編碼,能基於約定的就不配置)
6.2 POM
Maven項目的核心是pom.xml。POM(Project Object Model,項目對象模型)定義了項目的基本信息,用於描述項目如何構建,聲明項目依賴等。
- modelVersion:指定當前POM模型的版本,對Maven2和Maven3來說,他只能是4.0.0
- groupId:項目的所屬公司或組織的域名倒寫
- artifactId:如果該項目爲一個Maven模塊,則相當於項目名;如果一個項目包含多個子模塊,則它們該模塊的名稱;(一般和項目同名)
- version:該項目的版本信息
- name:項目名,作用只是一個更友好的項目名稱,不是必須的。
- packaging:打包方式,默認爲jar
6.3 依賴管理
Maven 一個核心的特性就是依賴管理。當我們處理多模塊的項目(包含成百上千個模塊或者子項目),模塊間的依賴關係就變得非常複雜,管理也變得很困難。針對此種情形,Maven 提供了一種高度控制的方法。
① 如何引入 jar 包
在代碼開發時,如果需要使用第三方 jar 包提供的類庫,那麼需要在 pom.xml 加入該 jar 包依賴。
例如:使用 zookeeper client
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/zookeeper -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>zookeeper</artifactId>
<version>3.3.1</version>
</dependency>
</dependencies>
② Maven 如何解析 jar 包依賴——傳遞依賴
如上所述,在 pom.xml 中引入 zookeeper jar 包依賴,當 Maven 解析該依賴時,需要引入的 jar 包不僅僅只有 zookeeper,還會有 zookeeper 內部依賴的 jar 包,還會有 zookeeper 內部依賴的 jar 包依賴的 jar 包......,依賴關係不斷傳遞,直至沒有依賴。
例如:上述 pom.xml 引入 zookeeper 依賴,實際引入的 jar 包有:
③ 依賴的範圍
有時依賴信息中除了目標 jar 包的座標還有一個 scope 設置,這就是依賴的範圍。依賴的範圍有幾個可選值,常用的有:compile、test、provided 三個,當然還有不常用的 runtime、system..
-
compile:默認範圍,編譯測試運行都有效
-
provided:在編譯和測試時有效
-
runtime:在測試和運行時有效
-
test:只在測試時有效
-
system:在編譯和測試時有效,與本機系統關聯,可移植性差
-
常用依賴範圍有效性總結
④ 包衝突如何產生?
舉個🌰:假設 A->B->C->D1, E->F->D2,D1,D2 分別爲 D 的不同版本。
如果 pom.xml 文件中引入了 A 和 E 之後,按照 Maven 傳遞依賴原則,工程內需要引入的實際 Jar 包將會有:A B C D1 和 E F D2,因此 D1,D2 將會產生包衝突。
⑤ 如何解決包衝突?
Maven 解析 pom.xml 文件時,同一個 jar 包只會保留一個,這樣有效的避免因引入兩個 jar 包導致的工程運行不穩定性。
Maven 默認處理策略
- 最短路徑優先
Maven 面對 D1 和 D2 時,會默認選擇最短路徑的那個 jar 包,即 D2。E->F->D2 比 A->B->C->D1 路徑短 1。 - 最先聲明優先
如果路徑一樣的話,舉個🌰: A->B->C1, E->F->C2 ,兩個依賴路徑長度都是 2,那麼就選擇最先聲明。
⑥ 移除依賴
如果我們不想通過 A->B->->D1 引入 D1 的話,那麼我們在聲明引入 A 的時候將 D1 排除掉,這樣也避免了包衝突。
舉個🌰:將 zookeeper 的 jline 依賴排除
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>zookeeper</artifactId>
<version>3.3.1</version>
<exclusions>
<exclusion>
<groupId>jline</groupId>
<artifactId>jline</artifactId>
</exclusion>
</exclusions>
</dependency>
⑦ 檢測包衝突工具
mvn dependency:help
mvn dependency:analyze
mvn dependency:tree
mvn dependency:tree -Dverbose
6.4 Repository(存儲庫)
Maven Repository/存儲庫,顧名思義是一個存儲JAR文件的倉庫,Maven根據項目中pom.xml文件中提供的jar包依賴信息,從存儲庫中查找並獲取需要的jar包。
① 分類
- Local Repository – 本地庫:Maven本地存儲庫是本機中的一個目錄。如果目錄不存在,執行maven時就會先創建它。
默認情況下,maven本地存儲庫是%USER_HOME%/.m2
目錄,例如:C:\Users\Kevin\.m2
- Central Repository – 中央庫:Maven中央庫主要放置公共jar包,是由apache maven社區創建的,中央庫的網址是http://repo1.maven.org/maven2,可以通過網址http://search.maven.org/#browse查看有哪些公共jar包。
- Remote Repository – 遠程庫:Maven遠程庫也是位於網絡上的存儲庫。例如一個公司可能有很多共享的jar包文件,就可以搭建一個公司內部的遠程庫,供衆多開發人員使用;中央庫可以認爲是一個特殊的遠程庫。
Maven搜索依賴項時,會按照:本地庫、中央庫和遠程庫的順序進行。
如果這些庫中沒找到依賴項,Maven將報錯。
6.5 生命週期
- default – 編譯源代碼並處理打包項目相關的所有事情
- clean – 清理構建輸出,包括生成的編譯類、JAR文件等
- site – 爲項目生成文檔
① Default 生命週期
- 清理(clean):刪除以前的編譯結果,爲重新編譯做好準備。
- 驗證(validate):驗證項目是否正確,所有必需的信息是否可用。
- 編譯(compile):將Java 源程序編譯爲字節碼文件。
- 測試(test):針對項目中的關鍵點進行測試,確保項目在迭代開發過程中關鍵點的正確性。
- 打包(package):將一個包含諸多文件的工程封裝爲一個壓縮文件用於安裝或部署。Java 工程對應 jar 包,Web工程對應 war 包。
- 安裝(install):在 Maven 環境下特指將打包的結果——jar 包或 war 包安裝到本地倉庫中。
- 報告:在每一次測試後以標準的格式記錄和展示測試結果。
- 部署(deploy):將打包的結果部署到遠程倉庫或將 war 包部署到服務器上運行。
② Clean 生命週期
Clean 生命週期一共包含了三個階段:
- pre-clean 執行一些需要在 clean 之前完成的工作
- clean 移除所有上一次構建生成的文件
- post-clean 執行一些需要在 clean 之後立刻完成的工作
③ Site 生命週期
- pre-site 執行一些需要在生成站點文檔之前完成的工作
- site 生成項目的站點文檔
- post-site 執行一些需要在生成站點文檔之後完成的工作,並且爲部署做準備
- site-deploy 將生成的站點文檔部署到特定的服務器上 這裏經常用到的是 site 階段和 site-deploy 階段,用以生成和發佈 Maven 站點,這可是 Maven 相當強大 的功能,Manager 比較喜歡,文檔及統計數據自動生成,很好看。
6.6 插件和目標
Maven實際上是一個插件執行框架,Maven中的所有任務都是由插件完成的。
Maven插件是構建目標的集合,也稱爲MOJO (Maven Old Java Object)。可以把插件理解爲一個類,而構建目標是類中的方法。構建階段包含一系列的構建目標,可以理解爲按順序調用各個插件中的構建目標(方法),然後一系列的構建階段組成一個構建生命週期。
構建目標可以綁定到多個構建階段,也可以不綁定,就像類的方法可以被調用,也可以不被調用。
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven.failsafe.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
這是一個故障安全插件的簡單配置,負責運行集成測試。可以看到,插件有兩個主要目標:
integration-test
: 運行集成測試verify
: 驗證所有通過的集成測試
插件類型
Maven提供了2種類型的插件:
- 構建類插件 – 在構建過程中執行,pom中
<build/>
元素中配置。 - 報告類插件 – 在文檔生成過程中執行,pom中
<reporting/>
元素中配置。
下面是一些maven內置的常用插件:
- clean
- compiler
- surefire
- jar
- war
- javadoc
- antrun
自定義插件
如果maven內置插件不能滿足項目需求,也可以開發自定義插件。
開發自定義插件可參考官網
6.7 繼承
- 爲什麼需要繼承機制? 由於非 compile 範圍的依賴信息是不能在“依賴鏈”中傳遞的,所以有需要的工程只能單獨配置
- 創建父工程 創建父工程和創建一般的 Java 工程操作一致,唯一需要注意的是:打包方式處要設置爲 pom
- 在子工程中引用父工程 ,從當前目錄到父項目的 pom.xml 文件的相對路徑
<parent>
<groupId>com.starfish.maven</groupId>
<artifactId>Parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 以當前文件爲基準的父工程pom.xml文件的相對路徑 -->
<relativePath>../Parent/pom.xml</relativePath>
</parent>
此時如果子工程的 groupId 和 version 如果和父工程重複則可以刪除。
- 在父工程中管理依賴 將 Parent 項目中的 dependencies 標籤,用 dependencyManagement 標籤括起來
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
複製代碼
在子項目中重新指定需要的依賴,刪除範圍和版本號
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
6.8 聚合
- 爲什麼要使用聚合?
將多個工程拆分爲模塊後,需要手動逐個安裝到倉庫後依賴才能夠生效。修改源碼後也需要逐個手動進 行 clean 操作。而使用了聚合之後就可以批量進行 Maven 工程的安裝、清理工作。
如何配置聚合? 在總的聚合工程中使用 modules/module 標籤組合,指定模塊工程的相對路徑即可
<!-- 配置聚合 -->
<modules>
<!-- 指定各個子工程的相對路徑 -->
<module>starfish-learn-grpc</module>
<module>starfish-learn-kafka</module>
<module>starfish-web-demo</module>
</modules>
6.9 profile
profile讓你能夠在特定場景下使用與基本配置不同的配置構建項目。你不需要創建多個單獨的POM文件,只需在單個POM文件中包含不同的profile配置,這些profile配置在特定場景下將覆蓋pom中的基本配置。
例如,項目中需要構建開發版本、測試版本以及正式版本,這些版本可以通過在pom文件中添加不同構建profile構建。執行maven時指定不同的構建profile就可以。
<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.qikegu.demo</groupId>
<artifactId>mybatis-demo</artifactId>
<version>1.0.0</version>
<profiles>
<profile>
<id>test</id>
<activation>...</activation>
<build>...</build>
<modules>...</modules>
<repositories>...</repositories>
<pluginRepositories>...</pluginRepositories>
<dependencies>...</dependencies>
<reporting>...</reporting>
<dependencyManagement>...</dependencyManagement>
<distributionManagement>...</distributionManagement>
</profile>
</profiles>
</project>
- profile中的元素將覆蓋POM中同名元素的值。
<activation>
設置觸發profile生效的條件- 也可在maven命令行中指定profile:
-P profile-name
參考
https://www.cnblogs.com/shengs/p/5517220.html
https://juejin.im/post/5e215a9ee51d453c951daa64
https://www.jianshu.com/p/f6ca45865025
https://www.qikegu.com/docs/2471