:notebook: 本文已歸檔到:「blog」php
Maven 是一個項目管理工具。它負責管理項目開發過程當中的幾乎全部的東西。html
maven 把項目的構建劃分爲不一樣的生命週期(lifecycle)。粗略一點的話,它這個過程(phase)包括:編譯、測試、打包、集成測試、驗證、部署。maven 中全部的執行動做(goal)都須要指明本身在這個過程當中的執行位置,而後 maven 執行的時候,就依照過程的發展依次調用這些 goal 進行各類處理。java
這個也是 maven 的一個基本調度機制。通常來講,位置稍後的過程都會依賴於以前的過程。固然,maven 一樣提供了配置文件,能夠依照用戶要求,跳過某些階段。linux
Maven 的標準工程結構以下:git
|-- pom.xml(maven的核心配置文件)
|-- src
|-- main
|-- java(java源代碼目錄)
|-- resources(資源文件目錄)
|-- test
|-- java(單元測試代碼目錄)
|-- target(輸出目錄,全部的輸出物都存放在這個目錄下)
|-- classes(編譯後的class文件存放處)
複製代碼
所謂的"約定優於配置",在 maven 中並非徹底不能夠修改的,他們只是一些配置的默認值而已。可是除非必要,並不須要去修改那些約定內容。maven 默認的文件存放結構以下:github
每個階段的任務都知道怎麼正確完成本身的工做,好比 compile 任務就知道從 src/main/java 下編譯全部的 java 文件,並把它的輸出 class 文件存放到 target/classes 中。web
對 maven 來講,採用"約定優於配置"的策略能夠減小修改配置的工做量,也能夠下降學習成本,更重要的是,給項目引入了統一的規範。算法
maven 使用以下幾個要素來惟必定位某一個輸出物:spring
maven 有本身的版本規範,通常是以下定義 <major version>
、<minor version>
、<incremental version>-<qualifier>
,好比 1.2.3-beta-01。要說明的是,maven 本身判斷版本的算法是 major,minor,incremental 部分用數字比 較,qualifier 部分用字符串比較,因此要當心 alpha-2 和 alpha-15 的比較關係,最好用 alpha-02 的格式。apache
maven 在版本管理時候可使用幾個特殊的字符串 SNAPSHOT,LATEST,RELEASE。好比"1.0-SNAPSHOT"。各個部分的含義和處理邏輯以下說明:
Linux 環境安裝可使用我寫一鍵安裝腳本:github.com/dunwu/os-tu…
注意:安裝 maven 以前,必須先確保你的機器中已經安裝了 JDK。
(1)解壓壓縮包(以 apache-maven-3.3.9-bin.zip 爲例)
(2)添加環境變量 MAVEN_HOME,值爲 apache-maven-3.3.9 的安裝路徑
(3)在 Path 環境變量的變量值末尾添加%MAVEN_HOME%\bin
(4)在 cmd 輸入 mvn –version,若是出現 maven 的版本信息,說明配置成功。
從中央倉庫下載的 jar 包,都會統一存放到本地倉庫中。咱們須要配置本地倉庫的位置。
打開 maven 安裝目錄,打開 conf 目錄下的 setting.xml 文件。
能夠參照下圖配置本地倉儲位置。
(1)建立 Maven 工程
依次點擊 File -> New -> Project 打開建立工程對話框,選擇 Maven 工程。
(2)輸入項目信息
(3)點擊 Intellij 側邊欄中的 Maven 工具界面,有幾個能夠直接使用的 maven 命令,能夠幫助你進行構建。
(1)Maven 插件
在 Eclipse 中建立 Maven 工程,須要安裝 Maven 插件。
通常較新版本的 Eclipse 都會帶有 Maven 插件,若是你的 Eclipse 中已經有 Maven 插件,能夠跳過這一步驟。
點擊 Help -> Eclipse Marketplace,搜索 maven 關鍵字,選擇安裝紅框對應的 Maven 插件。
(2)Maven 環境配置
點擊 Window -> Preferences
以下圖所示,配置 settings.xml 文件的位置
(3)建立 Maven 工程
File -> New -> Maven Project -> Next,在接下來的窗口中會看到一大堆的項目模板,選擇合適的模板。
接下來設置項目的參數,以下:
groupId是項目組織惟一的標識符,實際對應 JAVA 的包的結構,是 main 目錄裏 java 的目錄結構。
artifactId就是項目的惟一的標識符,實際對應項目的名稱,就是項目根目錄的名稱。
點擊 Finish,Eclipse 會建立一個 Maven 工程。
(4)使用 Maven 進行構建
Eclipse 中構建方式
在 Elipse 項目上右擊 -> Run As 就能看到不少 Maven 操做。這些操做和 maven 命令是等效的。例如 Maven clean,等同於 mvn clean 命令。
你也能夠點擊 Maven build,輸入組合命令,並保存下來。以下圖:
Maven 命令構建方式
固然,你也能夠直接使用 maven 命令進行構建。
進入工程所在目錄,輸入 maven 命令就能夠了。
在 Maven 工程中添加依賴 jar 包,很簡單,只要在 POM 文件中引入對應的<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>com.zp.maven</groupId>
<artifactId>MavenDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>MavenDemo</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>3.8.1</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
複製代碼
<dependency>
標籤最經常使用的四個屬性標籤:
<groupId>
- 項目組織惟一的標識符,實際對應 JAVA 的包的結構。<artifactId>
- 項目惟一的標識符,實際對應項目的名稱,就是項目根目錄的名稱。<version>
- jar 包的版本號。能夠直接填版本數字,也能夠在 properties 標籤中設置屬性值。<scope>
- jar 包的做用範圍。能夠填寫 compile、runtime、test、system 和 provided。用來在編譯、測試等場景下選擇對應的 classpath。能夠在 mvnrepository.com/ 站點搜尋你想要的 jar 包版本
例如,想要使用 log4j,能夠找到須要的版本號,而後拷貝對應的 maven 標籤信息,將其添加到 pom .xml 文件中。
要添加 Maven 插件,能夠在 pom.xml 文件中添加 <plugin>
標籤。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
複製代碼
<configuration>
標籤用來配置插件的一些使用參數。
假設要建立一個父 maven 工程,它有兩個子工程:my-app 和 my-webapp:
+- pom.xml
+- my-app
| +- pom.xml
| +- src
| +- main
| +- java
+- my-webapp
| +- pom.xml
| +- src
| +- main
| +- webapp
複製代碼
app 工程的 pom.xml 以下,重點在於在 modules 中引入兩個子 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>com.mycompany.app</groupId>
<artifactId>app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>my-app</module>
<module>my-webapp</module>
</modules>
</project>
複製代碼
選擇編譯 XXX 時,會依次對它的全部 Module 執行相同操做。
更多詳情請參考:maven.apache.org/plugins/
maven-antrun-plugin 能讓用戶在 Maven 項目中運行 Ant 任務。用戶能夠直接在該插件的配置以 Ant 的方式編寫 Target, 而後交給該插件的 run 目標去執行。在一些由 Ant 往 Maven 遷移的項目中,該插件尤爲有用。此外當你發現須要編寫一些自定義程度很高的任務,同時又覺 得 Maven 不夠靈活時,也能夠以 Ant 的方式實現之。maven-antrun-plugin 的 run 目標一般與生命週期綁定運行。
Archtype 指項目的骨架,Maven 初學者最開始執行的 Maven 命令可能就是mvn archetype:generate,這實際上就是讓 maven-archetype-plugin 生成一個很簡單的項目骨架,幫助開發者快速上手。可能也有人看到一些文檔寫了mvn archetype:create, 但實際上 create 目標已經被棄用了,取而代之的是 generate 目標,該目標使用交互式的方式提示用戶輸入必要的信息以建立項目,體驗更好。 maven-archetype-plugin 還有一些其餘目標幫助用戶本身定義項目原型,例如你由一個產品須要交付給不少客戶進行二次開發,你就能夠爲 他們提供一個 Archtype,幫助他們快速上手。
maven-assembly-plugin 的用途是將項目打包,該包可能包含了項目的可執行文件、源代碼、readme、平臺腳本等等。 maven-assembly-plugin 支持各類主流的格式如 zip、tar.gz、jar 和 war 等,具體打包哪些文件是高度可控的,例如用戶能夠 按文件級別的粒度、文件集級別的粒度、模塊級別的粒度、以及依賴級別的粒度控制打包,此外,包含和排除配置也是支持的。maven-assembly- plugin 要求用戶使用一個名爲assembly.xml
的元數據文件來表述打包,它的 single 目標能夠直接在命令行調用,也能夠被綁定至生命週期。
maven-dependency-plugin 最大的用途是幫助分析項目依賴,dependency:list可以列出項目最終解析到的依賴列表,dependency:tree能進一步的描繪項目依賴樹,dependency:analyze能夠告訴你項目依賴潛在的問題,若是你有直接使用到的卻未聲明的依賴,該目標就會發出警告。maven-dependency-plugin 還有不少目標幫助你操做依賴文件,例如dependency:copy-dependencies能將項目依賴從本地 Maven 倉庫複製到某個特定的文件夾下面。
在一個稍大一點的組織或團隊中,你沒法保證全部成員都熟悉 Maven,那他們作一些比較愚蠢的事情就會變得很正常,例如給項目引入了外部的 SNAPSHOT 依賴而致使構建不穩定,使用了一個與你們不一致的 Maven 版本而常常抱怨構建出現詭異問題。maven-enforcer- plugin 可以幫助你避免之類問題,它容許你建立一系列規則強制你們遵照,包括設定 Java 版本、設定 Maven 版本、禁止某些依賴、禁止 SNAPSHOT 依賴。只要在一個父 POM 配置規則,而後讓你們繼承,當規則遭到破壞的時候,Maven 就會報錯。除了標準的規則以外,你還能夠擴展該插 件,編寫本身的規則。maven-enforcer-plugin 的 enforce 目標負責檢查規則,它默認綁定到生命週期的 validate 階段。
maven-help-plugin 是一個小巧的輔助工具,最簡單的help:system能夠打印全部可用的環境變量和 Java 系統屬性。help:effective-pom和help:effective-settings最 爲有用,它們分別打印項目的有效 POM 和有效 settings,有效 POM 是指合併了全部父 POM(包括 Super POM)後的 XML,當你不肯定 POM 的某些信息從何而來時,就能夠查看有效 POM。有效 settings 同理,特別是當你發現本身配置的 settings.xml 沒有生效時,就能夠用help:effective-settings來驗證。此外,maven-help-plugin 的 describe 目標能夠幫助你描述任何一個 Maven 插件的信息,還有 all-profiles 目標和 active-profiles 目標幫助查看項目的 Profile。
maven-release-plugin 的用途是幫助自動化項目版本發佈,它依賴於 POM 中的 SCM 信息。release:prepare用來準備版本發佈,具體的工做包括檢查是否有未提交代碼、檢查是否有 SNAPSHOT 依賴、升級項目的 SNAPSHOT 版本至 RELEASE 版本、爲項目打標籤等等。release:perform則 是簽出標籤中的 RELEASE 源碼,構建併發布。版本發佈是很是瑣碎的工做,它涉及了各類檢查,並且因爲該工做僅僅是偶爾須要,所以手動操做很容易遺漏一 些細節,maven-release-plugin 讓該工做變得很是快速簡便,不易出錯。maven-release-plugin 的各類目標一般直接在 命令行調用,由於版本發佈顯然不是平常構建生命週期的一部分。
爲了使項目結構更爲清晰,Maven 區別對待 Java 代碼文件和資源文件,maven-compiler-plugin 用來編譯 Java 代碼,maven-resources-plugin 則用來處理資源文件。默認的主資源文件目錄是src/main/resources
,不少用戶會須要添加額外的資源文件目錄,這個時候就能夠經過配置 maven-resources-plugin 來實現。此外,資源文件過濾也是 Maven 的一大特性,你能夠在資源文件中使用*${propertyName}*形式的 Maven 屬性,而後配置 maven-resources-plugin 開啓對資源文件的過濾,以後就能夠針對不一樣環境經過命令行或者 Profile 傳入屬性的值,以實現更爲靈活的構建。
多是因爲歷史的緣由,Maven 2.3 中用於執行測試的插件不是 maven-test-plugin,而是 maven-surefire-plugin。其實大部分時間內,只要你的測試 類遵循通用的命令約定(以 Test 結尾、以 TestCase 結尾、或者以 Test 開頭),就幾乎不用知曉該插件的存在。然而在當你想要跳過測試、排除某些 測試類、或者使用一些 TestNG 特性的時候,瞭解 maven-surefire-plugin 的一些配置選項就頗有用了。例如 mvn test -Dtest=FooTest 這樣一條命令的效果是僅運行 FooTest 測試類,這是經過控制 maven-surefire-plugin 的 test 參數實現的。
Maven 默認只容許指定一個主 Java 代碼目錄和一個測試 Java 代碼目錄,雖然這實際上是個應當儘可能遵照的約定,但偶爾你仍是會但願可以指定多個 源碼目錄(例如爲了應對遺留項目),build-helper-maven-plugin 的 add-source 目標就是服務於這個目的,一般它被綁定到 默認生命週期的 generate-sources 階段以添加額外的源碼目錄。須要強調的是,這種作法仍是不推薦的,由於它破壞了 Maven 的約定,並且可能會遇到其餘嚴格遵照約定的插件工具沒法正確識別額外的源碼目錄。
build-helper-maven-plugin 的另外一個很是有用的目標是 attach-artifact,使用該目標你能夠以 classifier 的形式選取部分項目文件生成附屬構件,並同時 install 到本地倉庫,也能夠 deploy 到遠程倉庫。
exec-maven-plugin 很好理解,顧名思義,它能讓你運行任何本地的系統程序,在某些特定狀況下,運行一個 Maven 外部的程序可能就是最簡單的問題解決方案,這就是exec:exec的 用途,固然,該插件還容許你配置相關的程序運行參數。除了 exec 目標以外,exec-maven-plugin 還提供了一個 java 目標,該目標要求你 提供一個 mainClass 參數,而後它可以利用當前項目的依賴做爲 classpath,在同一個 JVM 中運行該 mainClass。有時候,爲了簡單的 演示一個命令行 Java 程序,你能夠在 POM 中配置好 exec-maven-plugin 的相關運行參數,而後直接在命令運行mvn exec:java 以查看運行效果。
在進行 Web 開發的時候,打開瀏覽器對應用進行手動的測試幾乎是沒法避免的,這種測試方法一般就是將項目打包成 war 文件,而後部署到 Web 容器 中,再啓動容器進行驗證,這顯然十分耗時。爲了幫助開發者節省時間,jetty-maven-plugin 應運而生,它徹底兼容 Maven 項目的目錄結構,可以週期性地檢查源文件,一旦發現變動後自動更新到內置的 Jetty Web 容器中。作一些基本配置後(例如 Web 應用的 contextPath 和自動掃描變動的時間間隔),你只要執行 mvn jetty:run ,而後在 IDE 中修改代碼,代碼經 IDE 自動編譯後產生變動,再由 jetty-maven-plugin 偵測到後更新至 Jetty 容器,這時你就能夠直接 測試 Web 頁面了。須要注意的是,jetty-maven-plugin 並非宿主於 Apache 或 Codehaus 的官方插件,所以使用的時候須要額外 的配置settings.xml
的 pluginGroups 元素,將 org.mortbay.jetty 這個 pluginGroup 加入。
不少 Maven 用戶遇到過這樣一個問題,當項目包含大量模塊的時候,爲他們集體更新版本就變成一件煩人的事情,到底有沒有自動化工具能幫助完成這件 事情呢?(固然你可使用 sed 之類的文本操做工具,不過不在本文討論範圍)答案是確定的,versions-maven- plugin 提供了不少目標幫助你管理 Maven 項目的各類版本信息。例如最經常使用的,命令 mvn versions:set -DnewVersion=1.1-SNAPSHOT 就能幫助你把全部模塊的版本更新到 1.1-SNAPSHOT。該插件還提供了其餘一些頗有用的目標,display-dependency- updates 能告訴你項目依賴有哪些可用的更新;相似的 display-plugin-updates 能告訴你可用的插件更新;而後 use- latest-versions 能自動幫你將全部依賴升級到最新版本。最後,若是你對所作的更改滿意,則可使用 mvn versions:commit 提交,不滿意的話也可使用 mvn versions:revert 進行撤銷。
更詳細命令說明請參考:maven.apache.org/guides/intr…
生命週期 | 階段描述 |
---|---|
mvn validate | 驗證項目是否正確,以及全部爲了完整構建必要的信息是否可用 |
mvn generate-sources | 生成全部須要包含在編譯過程當中的源代碼 |
mvn process-sources | 處理源代碼,好比過濾一些值 |
mvn generate-resources | 生成全部須要包含在打包過程當中的資源文件 |
mvn process-resources | 複製並處理資源文件至目標目錄,準備打包 |
mvn compile | 編譯項目的源代碼 |
mvn process-classes | 後處理編譯生成的文件,例如對 Java 類進行字節碼加強(bytecode enhancement) |
mvn generate-test-sources | 生成全部包含在測試編譯過程當中的測試源碼 |
mvn process-test-sources | 處理測試源碼,好比過濾一些值 |
mvn generate-test-resources | 生成測試須要的資源文件 |
mvn process-test-resources | 複製並處理測試資源文件至測試目標目錄 |
mvn test-compile | 編譯測試源碼至測試目標目錄 |
mvn test | 使用合適的單元測試框架運行測試。這些測試應該不須要代碼被打包或發佈 |
mvn prepare-package | 在真正的打包以前,執行一些準備打包必要的操做。這一般會產生一個包的展開的處理過的版本(將會在 Maven 2.1+中實現) |
mvn package | 將編譯好的代碼打包成可分發的格式,如 JAR,WAR,或者 EAR |
mvn pre-integration-test | 執行一些在集成測試運行以前須要的動做。如創建集成測試須要的環境 |
mvn integration-test | 若是有必要的話,處理包併發布至集成測試能夠運行的環境 |
mvn post-integration-test | 執行一些在集成測試運行以後須要的動做。如清理集成測試環境。 |
mvn verify | 執行全部檢查,驗證包是有效的,符合質量規範 |
mvn install | 安裝包至本地倉庫,以備本地的其它項目做爲依賴使用 |
mvn deploy | 複製最終的包至遠程倉庫,共享給其它開發人員和項目(一般和一次正式的發佈相關) |
使用參數
-Dmaven.test.skip=true
: 跳過單元測試(eg: mvn clean package -Dmaven.test.skip=true)
dependencyManagement 是表示依賴 jar 包的聲明,即你在項目中的 dependencyManagement 下聲明瞭依賴,maven 不會加載該依賴,dependencyManagement 聲明能夠被繼承。
dependencyManagement 的一個使用案例是當有父子項目的時候,父項目中能夠利用 dependencyManagement 聲明子項目中須要用到的依賴 jar 包,以後,當某個或者某幾個子項目須要加載該插件的時候,就能夠在子項目中 dependencies 節點只配置 groupId 和 artifactId 就能夠完成插件的引用。
dependencyManagement 主要是爲了統一管理插件,確保全部子項目使用的插件版本保持一致,相似的還有 plugins 和 pluginManagement。
錯誤現象
修改 JDK 版本,指定 maven-compiler-plugin 的 source 和 target 爲 1.8 。
而後,在 Intellij IDEA 中執行 maven 指令,報錯:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.0:compile (default-compile) on project apollo-common: Fatal error compiling: 無效的目標版本: 1.8 -> [Help 1]
複製代碼
錯誤緣由
maven 的 JDK 源與指定的 JDK 編譯版本不符。
排錯手段
Project SDK 是否正確
SDK 路徑是否正確
JDK for importer 是否正確
Runner 是否正確
在 Idea 中,選中 Module,使用 Ctrl+Alt+Shift+U,打開依賴圖,檢索是否存在重複引用的狀況。若是存在重複引用,能夠將多餘的引用刪除。
可使用 spring-boot-maven-plugin 插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
複製代碼
若是引入了第三方 jar 包,如何打包?
首先,要添加依賴
<dependency>
<groupId>io.github.dunwu</groupId>
<artifactId>dunwu-common</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/dunwu-common-1.0.0.jar</systemPath>
</dependency>
複製代碼
接着,須要配置 spring-boot-maven-plugin 插件:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
複製代碼
採用相似 spring-boot-dependencies
的方式統一管理依賴版本。
spring-boot-dependencies 的 pom.xml 形式:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.4.RELEASE</version>
<packaging>pom</packaging>
<!-- 省略 -->
<!-- 依賴包版本管理 -->
<dependencyManagement>
<dependencies>
<!-- 省略 -->
</dependencies>
</dependencyManagement>
<build>
<!-- 插件版本管理 -->
<pluginManagement>
<plugins>
<!-- 省略 -->
</plugins>
</pluginManagement>
</build>
</project>
複製代碼
其餘項目引入 spring-boot-dependencies 來管理依賴版本的方式:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
複製代碼