Maven介紹

什麼是Maven

乍一看,Maven彷佛包含不少內容,但簡而言之,Maven試圖將模式應用於項目的構建基礎設施,以便經過提供使用最佳實踐的清晰路徑來促進理解和生產力。Maven本質上是一個項目管理和理解工具,所以提供了一種幫助管理的方法:html

  • Builds
  • Documentation
  • Reporting
  • Dependencies
  • SCMs
  • Releases
  • Distribution

歷史

Maven最初設計,是以簡化Jakarta Turbine項目的建設。在幾個項目,每一個項目包含了不一樣的Ant構建文件。 JAR檢查到CVS。java

目標

1)爲了使項目管理更加簡單。程序員

2)提供統一的構建系統。web

3)提供優質項目的資訊。sql

4)爲最佳實踐開發提供指導。數據庫

5)容許透明地遷移到新特性。apache

建立

mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false
複製代碼

生成的文件目錄:安全

my-app
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- com
    |           `-- mycompany
    |               `-- app
    |                   `-- App.java
    `-- test
        `-- java
            `-- com
                `-- mycompany
                    `-- app
                        `-- AppTest.java
複製代碼

建立一個工程

mvn package
複製代碼

結果:bash

...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 seconds
[INFO] Finished at: Thu Jul 07 21:34:52 CEST 2011
[INFO] Final Memory: 3M/6M
[INFO] ------------------------------------------------------------------------
複製代碼

與執行的第一個命令(architetype:generate)不一樣,您可能會注意到第二個命令只是一個單詞package。這不是一個目標,而是一個階段。階段是構建生命週期中的一個步驟,它是一個有序的階段序列。當一個階段被給定時,Maven將執行序列中的每一個階段,直到幷包括定義的階段。例如,若是咱們執行編譯階段,實際執行的階段是:服務器

validate
generate-sources
process-sources
generate-resources
process-resources
compile
複製代碼

編譯jar包

java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App
複製代碼

輸出以下:

Hello World!
複製代碼

Java9或者以後的版本

默認狀況下,Maven版本可能使用Maven -compiler-plugin的舊版本,與Java 9或更高版本不兼容。要針對Java 9或更高版本,您至少應該使用maven-compiler-plugin的3.6.0版本,並將maven.compiler.release屬性設置爲您要針對的Java版本(例如九、十、十一、12等)。 在下面的例子中,咱們將Maven項目配置爲使用Maven -compiler-plugin的3.8.1版本和目標Java 11:

<properties>
        <maven.compiler.release>11</maven.compiler.release>
    </properties>
 
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
複製代碼

Maven階段

  • validate: 驗證項目是正確的,而且全部必要的信息都是可用的。
  • compile: 編譯項目的源代碼。
  • test:使用合適的單元測試框架測試編譯後的源代碼。這些測試不該該要求打包或部署代碼。
  • package:將編譯後的代碼打包成可分發的格式,好比JAR。
  • integration-test: 若是須要,將包處理並部署到能夠運行集成測試的環境中。
  • verify: 運行任何檢查來驗證包是否有效並知足質量標準。
  • install: 將包安裝到本地存儲庫中,以便在本地的其餘項目中做爲依賴項使用。
  • deploy: 在集成或發佈環境中完成,將最終的包複製到遠程存儲庫,以便與其餘開發人員和項目共享。

在上面的缺省列表以外,還有兩個Maven生命週期值得注意。他們是:

  • clean: 清理先前構建建立的工件。
  • site: 爲這個項目生成站點文檔。

快速開始

建立工程

使用命令:

mvn -B archetype:generate \
  -DarchetypeGroupId=org.apache.maven.archetypes \
  -DgroupId=com.mycompany.app \
  -DartifactId=my-app
複製代碼

執行此命令後,您將注意到發生了一些事情。首先,您將注意到爲新項目建立了一個名爲my-app的目錄,該目錄包含一個名爲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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
複製代碼

pom.xml包含該項目的項目對象模型(POM)。POM是Maven中的基本工做單元。記住這一點很重要,由於Maven本質上是以項目爲中心的,由於一切都圍繞着項目的概念。簡而言之,POM包含關於項目的全部重要信息,本質上是一站式搜索,查找與項目相關的任何內容。理解POM很是重要,咱們鼓勵新用戶參考對POM的介紹。 這是一個很是簡單的POM,但仍然顯示每一個POM包含的關鍵元素 ,因此讓咱們逐一介紹一下,讓您熟悉POM的要點:

  • project 這是全部Maven pom.xml文件中的頂級元素。
  • modelVersion 此元素指示此POM使用的對象模型的版本。模型自己的版本更改很是不頻繁,但若是Maven開發人員認爲有必要更改模型,則必須更改模型,以確保使用的穩定性。
  • groupId 此元素指示建立項目的組織或組的惟一標識符。groupId是項目的關鍵標識符之一,一般基於組織的徹底限定域名。例如org.apache.maven。插件是全部Maven插件的指定groupId。
  • artifactId 此元素指示此項目生成的主要構件的惟一基名稱。項目的主要構件一般是一個JAR文件。像源包這樣的次要構件也使用artifactId做爲它們最終名稱的一部分。Maven生成的典型工件的形式是-.<擴展名>(例如,myapp-1.0.jar)。
  • packaging 此元素指示此構件(例如JAR、WAR、EAR等)要使用的包類型。這不只意味着若是生成的工件是JAR、WAR或EAR,還能夠指示做爲構建過程一部分使用的特定生命週期。(生命週期是咱們將在指南中進一步討論的主題。如今,請記住,項目的指定打包能夠在定製構建生命週期中發揮必定的做用。打包元素的默認值是JAR,所以您沒必要爲大多數項目指定此值。
  • version 此元素指示由項目生成的工件的版本。Maven在幫助您進行版本管理方面走了很長的路,您常常會在版本中看到快照設計器,這代表項目處於開發狀態。咱們將在本指南中進一步討論快照的使用及其工做原理。
  • name 此元素指示用於項目的顯示名稱。這一般在Maven生成的文檔中使用。
  • url 此元素指示能夠在何處找到項目的站點。這一般在Maven生成的文檔中使用。
  • description 此元素提供項目的基本描述。這一般在Maven生成的文檔中使用。

編譯Maven

切換到原型建立pom.xml的目錄:生成並執行如下命令編譯應用程序源代碼:

mvn compile
複製代碼

執行此命令後,您將看到以下輸出:

[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Quick Start Archetype
[INFO]    task-segment: [compile]
[INFO] ----------------------------------------------------------------------------
[INFO] artifact org.apache.maven.plugins:maven-resources-plugin: \
  checking for updates from central
...
[INFO] artifact org.apache.maven.plugins:maven-compiler-plugin: \
  checking for updates from central
...
[INFO] [resources:resources]
...
[INFO] [compiler:compile]
Compiling 1 source file to <dir>/my-app/target/classes
[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------------------------
[INFO] Total time: 3 minutes 54 seconds
[INFO] Finished at: Fri Sep 23 15:48:34 GMT-05:00 2005
[INFO] Final Memory: 2M/6M
[INFO] ----------------------------------------------------------------------------
複製代碼

第一次執行這個(或任何其餘)命令時,Maven將須要下載完成該命令所需的全部插件和相關依賴項。從Maven的乾淨安裝來看,這可能須要至關長的時間(在上面的輸出中,它花費了近4分鐘)。若是您再次執行該命令,Maven如今將擁有它所須要的東西,所以它不須要下載任何新內容,而且可以更快地執行該命令。

從輸出中能夠看到,編譯後的類放在${basedir}/target/classes中,這是Maven使用的另外一種標準約定。所以,若是您是一個敏銳的觀察者,您會注意到,經過使用標準約定,上面的POM很是小,您沒必要顯式地告訴Maven您的任何源文件在哪裏,或者輸出應該放在哪裏。經過遵循標準Maven約定,您能夠用不多的努力完成不少工做!做爲一個隨意的比較,讓咱們來看看您在Ant中爲了完成一樣的事情可能必須作些什麼。

如今,只需編譯一個應用程序源代碼樹,所示Ant腳本的大小與上面所示POM的大小基本相同。可是,咱們將看到咱們能夠用這個簡單的POM作更多的事情!

我如何編譯個人測試源並運行個人單元測試?

如今,您已經成功地編譯了應用程序的源代碼,而且已經有了一些須要編譯和執行的單元測試(由於每一個程序員老是編寫和執行他們的單元測試nudge nudge wink)。

執行如下命令:

mvn test
複製代碼

執行此命令後,您將看到以下輸出:

[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Quick Start Archetype
[INFO]    task-segment: [test]
[INFO] ----------------------------------------------------------------------------
[INFO] artifact org.apache.maven.plugins:maven-surefire-plugin: \
  checking for updates from central
...
[INFO] [resources:resources]
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [resources:testResources]
[INFO] [compiler:testCompile]
Compiling 1 source file to C:\Test\Maven2\test\my-app\target\test-classes
...
[INFO] [surefire:test]
[INFO] Setting reports dir: C:\Test\Maven2\test\my-app\target/surefire-reports
 
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
[surefire] Running com.mycompany.app.AppTest
[surefire] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
 
Results :
[surefire] Tests run: 1, Failures: 0, Errors: 0
 
[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------------------------
[INFO] Total time: 15 seconds
[INFO] Finished at: Thu Oct 06 08:12:17 MDT 2005
[INFO] Final Memory: 2M/8M
[INFO] ----------------------------------------------------------------------------
複製代碼

關於輸出須要注意的一些事情:

Maven此次下載了更多的依賴項。這些是執行測試所需的依賴項和插件(它已經擁有編譯所需的依賴項,不會再下載它們)。

在編譯和執行測試以前,Maven編譯主代碼(全部這些類都是最新的,由於自上次編譯以來,咱們沒有更改任何東西)。

若是你只是想編譯你的測試源(而不是執行測試),你能夠執行如下步驟:

mvn test-compile
複製代碼

如何建立一個JAR並將其安裝到本地存儲庫中?

製做JAR文件很是簡單,能夠經過執行如下命令來完成:

mvn package
複製代碼

若是您查看項目的POM,您會注意到打包元素被設置爲jar。Maven就是這樣知道如何從上面的命令生成JAR文件的(稍後咱們將對此進行更多討論)。如今能夠查看{basedir}/target目錄,您將看到生成的JAR文件。
如今,您將但願將生成的工件(JAR文件)安裝到本地存儲庫({user.home) /中。m2/repository是默認位置)。有關存儲庫的更多信息,您能夠參考咱們對存儲庫的介紹,可是讓咱們繼續安裝咱們的工件!執行如下命令:

mvn install
複製代碼

執行此命令後,應該會看到如下輸出:

[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Quick Start Archetype
[INFO]    task-segment: [install]
[INFO] ----------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] [compiler:compile]
Compiling 1 source file to <dir>/my-app/target/classes
[INFO] [resources:testResources]
[INFO] [compiler:testCompile]
Compiling 1 source file to <dir>/my-app/target/test-classes
[INFO] [surefire:test]
[INFO] Setting reports dir: <dir>/my-app/target/surefire-reports
 
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
[surefire] Running com.mycompany.app.AppTest
[surefire] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.001 sec
 
Results :
[surefire] Tests run: 1, Failures: 0, Errors: 0
 
[INFO] [jar:jar]
[INFO] Building jar: <dir>/my-app/target/my-app-1.0-SNAPSHOT.jar
[INFO] [install:install]
[INFO] Installing <dir>/my-app/target/my-app-1.0-SNAPSHOT.jar to \
   <local-repository>/com/mycompany/app/my-app/1.0-SNAPSHOT/my-app-1.0-SNAPSHOT.jar
[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------------------------
[INFO] Total time: 5 seconds
[INFO] Finished at: Tue Oct 04 13:20:32 GMT-05:00 2005
[INFO] Final Memory: 3M/8M
[INFO] ----------------------------------------------------------------------------
複製代碼

請注意surefire插件(執行測試)尋找包含在具備特定命名約定的文件中的測試。默認狀況下,測試包括:

  • **/*Test.java
  • **/Test*.java
  • **/*TestCase.java

默認不包括:

  • **/Abstract*Test.java
  • **/Abstract*TestCase.java

您已經完成了設置、構建、測試、打包和安裝典型Maven項目的過程。這多是絕大多數項目將使用Maven作的事情,若是您已經注意到,到目前爲止您所能作的一切都是由一個18行文件驅動的,即項目的模型或POM。若是您查看一個典型的Ant構建文件,該文件提供了與咱們到目前爲止已經實現的功能相同的功能,您將注意到它已是POM的兩倍大,而咱們纔剛剛開始!Maven提供了更多的功能,而不須要像如今這樣對POM進行任何添加。要從示例Ant構建文件中得到更多功能,必須不斷添加容易出錯的內容。

那麼你還能免費獲得什麼呢?有不少Maven插件能夠用上面所述的簡單POM開箱即用。咱們將在這裏特別提到一個,由於它是Maven很是寶貴的特性之一:不須要您作任何工做,這個POM就有足夠的信息爲您的項目生成一個web站點!您極可能想自定義Maven站點,但若是時間緊迫,您只需執行如下命令便可提供關於項目的基本信息:

mvn site
複製代碼

還有不少其餘獨立的目標也能夠執行,例如:

mvn clean
複製代碼

什麼是快照版本?

注意,下面顯示的pom.xml文件中的version標記的值有後綴:-SNAPSHOT

<project xmlns="http://maven.apache.org/POM/4.0.0"
  ...
  <groupId>...</groupId>
  <artifactId>my-app</artifactId>
  ...
  <version>1.0-SNAPSHOT</version>
  <name>Maven Quick Start Archetype</name>
  ...
複製代碼

快照值指的是沿着開發分支的「最新」代碼,不能保證代碼是穩定的或不變的。相反,「release」版本(任何沒有後綴SNAPSHOT的版本值)中的代碼是不變的。

換句話說,快照版本是最終「發佈」版本以前的「開發」版本。快照比它的發佈「更老」。

在發佈過程當中,x的一個版本。y-SNAPSHOT更改成x.y.發佈過程也將開發版本增長到x.(y+1)-SNAPSHOT。例如,版本1.0- snapshot做爲版本1.0發佈,而新的開發版本是版本1.1-SNAPSHOT。

我如何使用插件?

不管什麼時候您想爲Maven項目定製構建,均可以經過添加或從新配置插件來完成。

Maven 1.0用戶注意:在Maven 1.0中,您將向Maven .xml添加一些preGoal,並向project.properties添加一些條目。在這裏,狀況有點不一樣。

對於本例,咱們將配置Java編譯器以容許JDK 5.0源代碼。這是簡單的添加到您的POM:

...
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.3</version>
      <configuration>
        <source>1.5</source>
        <target>1.5</target>
      </configuration>
    </plugin>
  </plugins>
</build>
...
複製代碼

您將注意到Maven中的全部插件看起來都很像依賴項——在某些方面確實如此。這個插件將自動下載和使用-包括一個特定的版本,若是你要求它(默認是使用最新可用的)。

configuration元素將給定的參數應用於編譯器插件中的每一個目標。在上面的例子中,編譯器插件已經被用做構建過程的一部分,這只是改變了配置。還能夠向流程添加新目標,並配置特定的目標。有關這方面的信息,請參閱構建生命週期的介紹。

要了解插件的可用配置,能夠查看插件列表,並導航到正在使用的插件和目標。有關如何配置插件的可用參數的通常信息,請參閱配置插件的指南。

如何向JAR添加資源?

另外一個能夠知足的常見用例是將資源打包到JAR文件中,它不須要修改上面的POM。對於這個常見的任務,Maven再次依賴於標準目錄佈局,這意味着經過使用標準Maven約定,您只需將這些資源放在標準目錄結構中,就能夠將資源打包到jar中。

您能夠在下面的示例中看到,咱們添加了{basedir}/src/main/resources目錄,將但願打包到JAR中的任何資源放入其中。Maven使用的簡單規則是:{basedir}/src/main/resources目錄中放置的任何目錄或文件都打包在JAR中,從JAR的底部開始使用徹底相同的結構。

my-app
|-- pom.xml
`-- src
    |-- main
    |   |-- java
    |   |   `-- com
    |   |       `-- mycompany
    |   |           `-- app
    |   |               `-- App.java
    |   `-- resources
    |       `-- META-INF
    |           `-- application.properties
    `-- test
        `-- java
            `-- com
                `-- mycompany
                    `-- app
                        `-- AppTest.java
複製代碼

在咱們的例子中,咱們有一個META-INF目錄和一個應用程序。該目錄中的屬性文件。若是您打開Maven爲您建立的JAR並查看它,您將看到如下內容:

|-- META-INF
|   |-- MANIFEST.MF
|   |-- application.properties
|   `-- maven
|       `-- com.mycompany.app
|           `-- my-app
|               |-- pom.properties
|               `-- pom.xml
`-- com
    `-- mycompany
        `-- app
            `-- App.class
複製代碼

能夠看到,${basedir}/src/main/resources的內容能夠從JAR和咱們的應用程序的底部開始找到。application.properties文件在META-INF目錄中。您還會注意到其餘一些文件,好比META-INF/MANIFEST.MF,以及pom.xmlpom.properties文件。這些都是Maven中生成JAR的標準配置。若是您選擇,您能夠建立本身的清單,可是Maven將在缺省狀況下生成清單。(您還能夠修改默認清單中的條目。這個咱們之後再談。)pom.xmlpom.properties。屬性文件打包在JAR中,所以Maven生成的每一個構件都是自描述的,而且若是須要,還容許您在本身的應用程序中使用元數據。一個簡單的用途多是檢索應用程序的版本。在POM文件上操做須要使用一些Maven實用程序,可是可使用標準Java API使用這些屬性,以下所示:

#Generated by Maven
#Tue Oct 04 15:43:21 GMT-05:00 2005
version=1.0-SNAPSHOT
groupId=com.mycompany.app
artifactId=my-app
複製代碼

要將資源添加到單元測試的類路徑中,除了將資源放入的目錄爲${basedir}/src/test/resources以外,遵循與向JAR添加資源相同的模式。此時,您將擁有一個項目目錄結構,以下所示:

my-app
|-- pom.xml
`-- src
    |-- main
    |   |-- java
    |   |   `-- com
    |   |       `-- mycompany
    |   |           `-- app
    |   |               `-- App.java
    |   `-- resources
    |       `-- META-INF
    |           |-- application.properties
    `-- test
        |-- java
        |   `-- com
        |       `-- mycompany
        |           `-- app
        |               `-- AppTest.java
        `-- resources
            `-- test.properties
複製代碼

在單元測試中,您可使用以下簡單的代碼片斷來訪問測試所需的資源:

...
 
// Retrieve resource
InputStream is = getClass().getResourceAsStream( "/test.properties" );
 
// Do something with the resource
 
...
複製代碼

如何過濾資源文件?

有時,資源文件須要包含一個只能在構建時提供的值。要在Maven中實現這一點,可使用${}語法將包含值的屬性引用放到資源文件中。屬性能夠是pom中定義的值之一。xml,用戶設置中定義的值。xml,在外部屬性文件或系統屬性中定義的屬性。

要讓Maven在複製時過濾資源,只需將pom.xml中的資源目錄的filtering設置爲true:

<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>my-app</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
 
  <build>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
  </build>
</project>
複製代碼

您將注意到,咱們必須添加之前沒有的 build, resourcesresource元素。此外,咱們必須顯式地聲明資源位於src/main/resources目錄中。全部這些信息都是之前做爲默認值提供的,可是由於用於filtering的默認值是false,因此咱們必須將其添加到pom.xml中,以便覆蓋該默認值並將filtering設置爲true。

引用pom中定義的屬性。屬性名使用定義值的xml元素的名稱,容許「pom」做爲項目(根)元素的別名。所以${project.name}引用項目的名稱,${project.version}引用項目的版本,${project.build.finalName}是指在打包構建的項目時建立的文件的最終名稱,等等。請注意,POM的一些元素有默認值,所以不須要在pom.xml中顯式地定義這些值。相似地,可使用以「settings」開頭的屬性名引用用戶settings.xml中的值(例如${settings.localRepository}引用用戶的本地存儲庫的路徑)。

爲了繼續咱們的示例,讓咱們向application.properties添加幾個屬性(咱們把它放在src/main/resources目錄中),當資源被過濾時,它的值將被提供:

# application.properties
application.name=${project.name}
application.version=${project.version}
複製代碼

有了它,您能夠執行如下命令(process-resources是複製和過濾資源的構建生命週期階段):

mvn process-resources
複製代碼

target/classes下的application.properties(最終會進入jar)看起來是這樣的:

# application.properties
application.name=Maven Quick Start Archetype
application.version=1.0-SNAPSHOT
複製代碼

要引用外部文件中定義的屬性,只需在pom.xml中添加對該外部文件的引用。首先,讓咱們建立外部屬性文件並調用它:

src/main/filters/filter.properties:

# filter.properties
my.filter.value=hello!
複製代碼

接下來,咱們將在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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
 
  <build>
    <filters>
      <filter>src/main/filters/filter.properties</filter>
    </filters>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
  </build>
</project>
複製代碼

而後,若是咱們在應用程序中添加對該屬性的引用。屬性文件:

# application.properties
application.name=${project.name}
application.version=${project.version}
message=${my.filter.value}
複製代碼

mvn process-resources命令的下一個執行將把咱們的新屬性值放入application.properties。做爲定義my.filter.value 的替代方法。在外部文件中,您也能夠在pom.xml的properties部分中定義value屬性,您將獲得相同的效果(注意,我不須要對src/main/filters/filter.properties的引用):

<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>my-app</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
 
  <build>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
  </build>
 
  <properties>
    <my.filter.value>hello</my.filter.value>
  </properties>
</project>
複製代碼

過濾資源還能夠從系統屬性中獲取值;要麼是內置到Java中的系統屬性(好比java.version 或者user.home)。或在命令行上使用標準Java -D參數定義的屬性。爲了繼續這個示例,讓咱們更改咱們的應用程序。屬性文件看起來像這樣:

# application.properties
java.version=${java.version}
command.line.prop=${command.line.prop}
複製代碼

如今,當您執行如下命令時(注意command.line.prop的定義),application.properties將包含來自系統屬性的值。

mvn process-resources "-Dcommand.line.prop=hello again"
複製代碼

我如何使用外部依賴?

您可能已經注意到咱們做爲示例使用的POM中有一個dependencies元素。實際上,您一直在使用外部依賴項,但在這裏咱們將更詳細地討論它是如何工做的。有關更詳細的介紹,請參閱咱們對依賴機制的介紹。

pom.xml的dependencies部分列出了咱們的項目爲了構建而須要的全部外部依賴項(不管是在編譯時、測試時、運行時仍是其餘時候)。如今,咱們的項目只依賴於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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
複製代碼

對於每一個外部依賴項,至少須要定義4個東西:groupId、artifactId、version和scope。groupId、artifactId和版本與構建該依賴項的項目的pom.xml中給出的版本相同。scope元素指示項目如何使用該依賴項,能夠是compiletestruntime等值。有關能夠爲依賴項指定的全部內容的更多信息,請參見項目描述符引用(maven.apache.org/ref/3.6.1/m…)。

有了這些關於依賴項的信息,Maven將可以在構建項目時引用依賴項。Maven從哪裏引用依賴項?Maven查看本地存儲庫(${user.home}/.m2/repository是默認位置)來查找全部依賴項。在前一節中,咱們將項目中的構件(my-app-1.0- snap .jar)安裝到本地存儲庫中。一旦它安裝在那裏,另外一個項目就能夠將該jar引用爲依賴項,只需將依賴項信息添加到它的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">
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-other-app</artifactId>
  ...
  <dependencies>
    ...
    <dependency>
      <groupId>com.mycompany.app</groupId>
      <artifactId>my-app</artifactId>
      <version>1.0-SNAPSHOT</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>
複製代碼

那麼在其餘地方構建的依賴關係呢?它們如何進入個人本地存儲庫?當項目引用本地存儲庫中不可用的依賴項時,Maven將從遠程存儲庫下載該依賴項到本地存儲庫。您可能注意到Maven在構建第一個項目時下載了不少東西(這些下載是用於構建項目的各類插件的依賴項)。默認狀況下,能夠經過http://repo.maven.apache.org/maven2/找到(並瀏覽)Maven使用的遠程存儲庫。您還能夠設置本身的遠程存儲庫(多是您公司的一箇中央存儲庫)來代替或附加使用默認的遠程存儲庫。有關存儲庫的更多信息,請參閱存儲庫介紹。

讓咱們爲項目添加另外一個依賴項。假設咱們在代碼中添加了一些日誌記錄,而且須要添加log4j做爲依賴項。首先,咱們須要知道log4j的groupId、artifactId和版本。Maven中心上的適當目錄稱爲/maven2/log4j/log4j。在該目錄中有一個名爲maven-metada .xml的文件。log4j的maven-metada .xml是這樣的:

<metadata>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.1.3</version>
  <versioning>
    <versions>
      <version>1.1.3</version>
      <version>1.2.4</version>
      <version>1.2.5</version>
      <version>1.2.6</version>
      <version>1.2.7</version>
      <version>1.2.8</version>
      <version>1.2.11</version>
      <version>1.2.9</version>
      <version>1.2.12</version>
    </versions>
  </versioning>
</metadata>
複製代碼

從這個文件中,咱們能夠看到咱們想要的groupId是「log4j」,而artifactId是「log4j」。咱們看到有不少不一樣的版本值可供選擇;如今,咱們只使用最新版本1.2.12(一些maven-metada .xml文件也可能指定哪一個版本是當前版本)。在maven-metada .xml文件旁邊,咱們能夠看到與log4j庫的每一個版本對應的目錄。在這些文件中,咱們將找到實際的jar文件(例如log4j-1.2.12.jar)、pom文件(這是依賴項的pom.xml,表示它可能具備的任何進一步依賴項和其餘信息)和另外一個maven-metada .xml文件。還有一個md5文件對應於每一個文件,其中包含這些文件的md5散列。您可使用它對庫進行身份驗證,或者肯定您可能已經在使用某個特定庫的哪一個版本。

如今咱們知道了須要的信息,能夠將依賴項添加到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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.12</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>
複製代碼

依賴傳遞

Maven經過自動包含傳遞依賴項,避免了發現和指定您本身的依賴項所需的庫。

經過從指定的遠程存儲庫中讀取依賴項的項目文件,能夠簡化此功能。一般,這些項目的全部依賴項都將在您的項目中使用,就像項目從父項目繼承的依賴項或從依賴項繼承的依賴項同樣。

能夠收集依賴項的級別數量沒有限制。只有在發現循環依賴項時纔會出現問題。

使用傳遞依賴關係,所包含的庫的圖能夠快速增加得至關大。因爲這個緣由,有一些額外的功能限制哪些依賴關係包括在內:

依賴項中介——當遇到多個版本做爲依賴項時,它決定將選擇工件的哪一個版本。Maven選擇「最近的定義」。也就是說,它使用依賴樹中與項目最接近的依賴項的版本。您老是能夠經過在項目的POM中顯式聲明一個版原本保證該版本。請注意,若是依賴項樹中的兩個依賴項版本具備相同的深度,則第一個聲明將獲勝。

「最接近的定義」意味着所使用的版本將是依賴關係樹中最接近您的項目的版本。例如,若是A、B和C的依賴關係定義爲A -> B -> C -> D 2.0和A -> E -> D 1.0,那麼在構建A時將使用D 1.0,由於從A到D到E的路徑更短。您能夠在a中顯式地向d2.0添加依賴項,以強制使用d2.0。

依賴關係管理——這容許項目做者直接指定工件的版本,當它們遇到傳遞依賴項或沒有指定版本的依賴項時使用。在前面的示例中部分依賴直接添加到即便它是不能直接使用的a .相反,能夠包括D做爲依賴dependencyManagement部分和直接控制哪一個版本的D時使用,或者是引用。

依賴關係範圍——這容許您只包含適合當前構建階段的依賴關係。下面將對此進行更詳細的描述。

排除依賴關係——若是項目X依賴於項目Y,而項目Y依賴於項目Z,那麼項目X的全部者可使用「"exclusion」元素顯式地排除項目Z做爲依賴關係。

可選依賴項——若是項目Y依賴於項目Z,項目Y的全部者可使用「optional」元素將項目Z標記爲可選依賴項。當項目X依賴於項目Y時,X將只依賴於Y,而不依賴於Y的可選依賴項Z。(將可選依賴項視爲「默認排除」可能會有所幫助。)

雖然傳遞依賴項能夠隱式地包含所需的依賴項,但顯式地指定直接在源代碼中使用的依賴項是一個很好的實踐。這一最佳實踐證實了它的價值,特別是當項目的依賴項更改其依賴項時。

例如,假設您的項目指定一個依賴另外一個項目B, B和項目指定依賴項目C .若是你直接使用組件項目C,和你不指定項目C在您的項目中,它可能會致使構建失敗當項目B忽然更新/刪除項目C的依賴。

直接指定依賴關係的另外一個緣由是,它爲您的項目提供了更好的文檔:只需閱讀項目中的POM文件就能夠了解更多信息。

Maven還提供了依賴關係:分析插件目標來分析依賴關係:它有助於使這一最佳實踐更容易實現。

依賴範圍

依賴項的範圍——compile, runtime, test, systemprovided。用於計算用於編譯、測試等的各類類路徑。它還幫助肯定在這個項目的發行版中包含哪些工件。有關更多信息,請參見依賴機制。默認範圍是compile。

依賴關係管理是Maven的一個核心特性。管理單個項目的依賴關係很容易。管理由數百個模塊組成的多模塊項目和應用程序的依賴關係是可能的。Maven在使用定義良好的類路徑和庫版本定義、建立和維護可重複構建方面幫助很大。

依賴範圍用於限制依賴項的傳遞性,還用於影響用於各類構建任務的類路徑。

有6種適用範圍:

compile

這是默認範圍,若是沒有指定則使用。編譯依賴項在項目的全部類路徑中均可用。此外,這些依賴項將傳播到依賴的項目。

provided

這很像compile,但代表您但願JDK或容器在運行時提供依賴項。例如,當爲Java Enterprise Edition構建web應用程序時,您將對Servlet API和相關Java EE API的依賴scope設置爲provided,由於web容器提供了這些類。此範圍僅在編譯和測試類路徑上可用,且不可傳遞。

runtime

此範圍指示此依賴項不是編譯所需的,而是執行所需的。它位於運行時和測試類路徑中,但不在編譯類路徑中。

test

此範圍代表,應用程序的正常使用不須要依賴項,僅在測試編譯和執行階段可用。這個範圍不是可傳遞的。

system

除了必須顯式地提供包含它的JAR以外,此範圍與provided的相似。工件老是可用的,而且不會在存儲庫中查找。

import

此範圍僅在<dependencyManagement>部分的pom類型依賴項上受支持。它指示要用指定POM的<dependencyManagement>節中的有效依賴項列表替換依賴項。因爲替換了依賴項,具備導入範圍的依賴項實際上並不參與限制依賴項的傳遞性。

每一個範圍(import除外)都以不一樣的方式影響傳遞依賴關係,以下表所示。若是將依賴項設置爲左列中的做用域,則該依賴項與第一行中的做用域的傳遞依賴項將致使主項目中的依賴項,其做用域列在交集處。若是沒有列出範圍,則意味着將省略依賴項。

compile provided runtime test
compile compile(*) - runtime -
provided provided - provided -
runtime runtime - runtime -
test test - test -

(*)注意:這應該是運行時範圍,以便全部編譯依賴項必須顯式列出。可是,若是您所依賴的庫從另外一個庫擴展了一個類,那麼這兩個庫必須在編譯時可用。所以,即便編譯時依賴項是傳遞的,它們仍然做爲編譯範圍。

依賴管理

依賴項管理部分是集中化依賴項信息的機制。當您有一組繼承公共父類的項目時,能夠將全部關於依賴關係的信息放在公共POM中,並對子POMs中的構件有更簡單的引用。經過一些例子能夠很好地說明這種機制。給定這兩個延伸相同父節點的POMs:

Project A::

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-a</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>group-c</groupId>
          <artifactId>excluded-artifact</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>bar</type>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>
複製代碼

Project B:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>group-c</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>war</type>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
      <version>1.0</version>
      <type>bar</type>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
</project>
複製代碼

這兩個示例POMs共享一個公共依賴項,而且每一個POMs都有一個重要的依賴項。這些信息能夠像這樣放在父POM中:

<project>
  ...
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>group-a</groupId>
        <artifactId>artifact-a</artifactId>
        <version>1.0</version>
 
        <exclusions>
          <exclusion>
            <groupId>group-c</groupId>
            <artifactId>excluded-artifact</artifactId>
          </exclusion>
        </exclusions>
 
      </dependency>
 
      <dependency>
        <groupId>group-c</groupId>
        <artifactId>artifact-b</artifactId>
        <version>1.0</version>
        <type>war</type>
        <scope>runtime</scope>
      </dependency>
 
      <dependency>
        <groupId>group-a</groupId>
        <artifactId>artifact-b</artifactId>
        <version>1.0</version>
        <type>bar</type>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>
複製代碼

而後兩個孩子的poms變得簡單多了:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-a</artifactId>
    </dependency>
 
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
      <!-- This is not a jar dependency, so we must specify type. -->
      <type>bar</type>
    </dependency>
  </dependencies>
</project>
複製代碼
<project>
  ...
  <dependencies>
    <dependency>
      <groupId>group-c</groupId>
      <artifactId>artifact-b</artifactId>
      <!-- This is not a jar dependency, so we must specify type. -->
      <type>war</type>
    </dependency>
 
    <dependency>
      <groupId>group-a</groupId>
      <artifactId>artifact-b</artifactId>
      <!-- This is not a jar dependency, so we must specify type. -->
      <type>bar</type>
    </dependency>
  </dependencies>
</project>
複製代碼

注意:在這兩個依賴項引用中,咱們必須指定<type/>元素。這是由於,針對dependencyManagement部分匹配依賴項引用的最小信息集其實是{groupId、artifactId、type、classifier}。在許多狀況下,這些依賴關係將引用沒有分類器的jar構件。這容許咱們將標識簡寫爲{groupId, artifactId},由於類型字段的缺省值是jar,缺省分類器是null。

依賴項管理部分的第二個很是重要的用途是控制傳遞依賴項中使用的工件的版本。例如,考慮如下項目:

Project A:

<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:

<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>
複製代碼

當maven在項目B上運行時,工件a、b、c和d的1.0版本將被使用,而不考慮它們的pom中指定的版本。

a和c都聲明爲項目的依賴項,所以因爲依賴項中介使用1.0版本。二者都有運行時範圍,由於它是直接指定的。

b在b的父依賴項管理部分中定義,因爲依賴項管理對於傳遞依賴項優先於依賴項中介,因此若是在a或c的pom中引用1.0版本,則選擇1.0版本。b也有編譯範圍。

最後,因爲d是在B的依賴項管理部分中指定的,若是d是a或c的依賴項(或傳遞依賴項),那麼將選擇1.0版本——一樣,由於依賴項管理優先於依賴項中介,並且當前pom的聲明優先於其父聲明。

有關依賴項管理標記的引用信息可從項目描述符引用得到。

引入依賴項

上一節中的示例描述瞭如何經過繼承指定託管依賴項。然而,在較大的項目中,這多是不可能完成的,由於項目只能從單個父級繼承。爲了適應這一點,項目能夠從其餘項目導入托管依賴項。這是經過將pom工件聲明爲具備「import」範圍的依賴項來實現的。

Project B:

<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>
複製代碼

假設A是前面示例中定義的pom,那麼最終結果將是相同的。除了d以外,A的全部託管依賴項都將被合併到B中,由於d是在這個pom中定義的。

Project X:

<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>maven</groupId>
 <artifactId>X</artifactId>
 <packaging>pom</packaging>
 <name>X</name>
 <version>1.0</version>
 
 <dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>test</groupId>
       <artifactId>a</artifactId>
       <version>1.1</version>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>b</artifactId>
       <version>1.0</version>
       <scope>compile</scope>
     </dependency>
   </dependencies>
 </dependencyManagement>
</project>
複製代碼

Project Y:

<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>maven</groupId>
 <artifactId>Y</artifactId>
 <packaging>pom</packaging>
 <name>Y</name>
 <version>1.0</version>
 
 <dependencyManagement>
   <dependencies>
     <dependency>
       <groupId>test</groupId>
       <artifactId>a</artifactId>
       <version>1.2</version>
     </dependency>
     <dependency>
       <groupId>test</groupId>
       <artifactId>c</artifactId>
       <version>1.0</version>
       <scope>compile</scope>
     </dependency>
   </dependencies>
 </dependencyManagement>
</project>
複製代碼

Project Z:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>maven</groupId>
  <artifactId>Z</artifactId>
  <packaging>pom</packaging>
  <name>Z</name>
  <version>1.0</version>
 
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>maven</groupId>
        <artifactId>X</artifactId>
        <version>1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>maven</groupId>
        <artifactId>Y</artifactId>
        <version>1.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>
複製代碼

在上面的例子中,Z從X和Y中導入托管依賴項。然而,X和Y都包含依賴項a。

這個過程是遞歸的。例如,若是X導入另外一個pom Q,當Z被處理時,它將簡單地顯示Q的全部託管依賴項都在X中定義。

當用於定義相關工件的「庫」時,導入是最有效的,這些工件一般是多項目構建的一部分。一個項目使用這些庫中的一個或多個構件是至關常見的。然而,有時很難使用構件將項目中的版本與庫中分發的版本保持同步。下面的模式說明了如何建立「物料清單」(BOM)供其餘項目使用。

項目的根是BOM pom。它定義了將在庫中建立的全部構件的版本。但願使用該庫的其餘項目應該將此pom導入其pom的dependencyManagement部分。

<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>${project2Version}</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
 
  <modules>
    <module>parent</module>
  </modules>
</project>
複製代碼

父子項目以BOM pom做爲父項目。這是一個普通的多項目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>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>
複製代碼

接下來是實際的項目poms:

<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</packaging>
 
  <dependencies>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</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>
  <groupId>com.test</groupId>
  <artifactId>use</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>
 
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.test</groupId>
        <artifactId>bom</artifactId>
        <version>1.0.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.test</groupId>
      <artifactId>project1</artifactId>
    </dependency>
    <dependency>
      <groupId>com.test</groupId>
      <artifactId>project2</artifactId>
    </dependency>
  </dependencies>
</project>
複製代碼

系統依賴

重要提示:這是不推薦的。

與範圍系統的依賴關係老是可用的,而且不會在存儲庫中查找。它們一般用於告訴Maven JDK或VM提供的依賴關係。所以,系統依賴關係對於解決對工件的依賴關係特別有用,這些工件如今由JDK提供,可是在之前能夠單獨下載。典型的例子是JDBC標準擴展或Java身份驗證和受權服務(JAAS)。

一個簡單的例子是:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>javax.sql</groupId>
      <artifactId>jdbc-stdext</artifactId>
      <version>2.0</version>
      <scope>system</scope>
      <systemPath>${java.home}/lib/rt.jar</systemPath>
    </dependency>
  </dependencies>
  ...
</project>
複製代碼

若是您的工件是由JDK的tools.jar提供的,系統路徑定義以下:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>sun.jdk</groupId>
      <artifactId>tools</artifactId>
      <version>1.5.0</version>
      <scope>system</scope>
      <systemPath>${java.home}/../lib/tools.jar</systemPath>
    </dependency>
  </dependencies>
  ...
</project>
複製代碼

Optional & Exclusion

本節討論可選的依賴項和依賴項排除。這將幫助用戶瞭解它們是什麼、什麼時候以及如何使用它們。它還解釋了爲何排除是在每一個依賴項的基礎上而不是在POM級別進行的。

可選依賴關係

當不可能(不管出於什麼緣由)將項目分割爲子模塊時,將使用可選依賴項。其思想是,一些依賴關係僅用於項目中的某些特性,若是不使用該特性,就不須要這些依賴關係。理想狀況下,這樣的特性將被劃分爲依賴於核心功能項目的子模塊。這個新的子項目將只有非可選的依賴項,由於若是您決定使用子項目的功能,就須要全部這些依賴項。

然而,因爲項目不能被分割(不管出於什麼緣由),這些依賴項聲明爲可選的。若是用戶但願使用與可選依賴項相關的功能,則必須在本身的項目中從新聲明該可選依賴項。這不是處理這種狀況的最清楚的方法,可是可選依賴項和依賴項排除都是權宜之計。

爲何使用可選依賴項?

可選依賴項節省空間和內存。它們防止有問題的jar(違反許可協議或致使類路徑問題)被綁定到WAR、EAR、fat jar或相似的jar中。

如何使用optional標籤

經過在依賴項聲明中將<optional>元素設置爲true,能夠將依賴項聲明爲可選:

<project>
  ...
  <dependencies>
    <!-- declare the dependency to be set as optional -->
    <dependency>
      <groupId>sample.ProjectA</groupId>
      <artifactId>Project-A</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
      <optional>true</optional> <!-- value will be true or false only -->
    </dependency>
  </dependencies>
</project>
複製代碼

可選依賴項如何工做?

Project-A -> Project-B
複製代碼

上面的圖表說明項目a依賴於項目b。當A在其POM中將B聲明爲可選依賴項時,此關係保持不變。它就像一個普通的構建,其中Project-B將被添加到Project-A的類路徑中。

Project-X -> Project-A
複製代碼

當另外一個項目(project - x)在其POM中將project - a聲明爲依賴項時,依賴項的可選屬性將生效。Project-B不包含在Project-X的類路徑中。您須要在項目X的POM中直接聲明它,以便將B包含在X的類路徑中。

例子

假設有一個名爲X2的項目,它具備與Hibernate相似的功能。它支持許多數據庫,如MySQL、PostgreSQL和Oracle的幾個版本。每一個受支持的數據庫都須要額外依賴於驅動程序jar。全部這些依賴項都須要在編譯時構建X2。可是,您的項目只使用一個特定的數據庫,其餘數據庫不須要驅動程序。X2能夠將這些依賴項聲明爲可選的,這樣當您的項目在其POM中將X2聲明爲直接依賴項時,X2支持的全部驅動程序不會自動包含在項目的類路徑中。您的項目必須包含對它所使用的數據庫的特定驅動程序的顯式依賴。

Dependency Exclusions

因爲Maven臨時解析依賴項,因此項目的類路徑中可能包含不須要的依賴項。例如,某個較老的jar可能存在安全問題,或者與您正在使用的Java版本不兼容。爲了解決這個問題,Maven容許您排除特定的依賴項。排除是針對POM中的特定依賴項設置的,而且針對特定的groupId和artifactId。當您構建項目時,該構件將不會經過聲明排除的依賴項添加到項目的類路徑中。

如何使用dependency exclusions

在包含有問題jar的<dependency>元素中添加一個<exclude>元素。

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>sample.ProjectA</groupId>
      <artifactId>Project-A</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
      <exclusions>
        <exclusion>  <!-- declare the exclusion here -->
          <groupId>sample.ProjectB</groupId>
          <artifactId>Project-B</artifactId>
        </exclusion>
      </exclusions> 
    </dependency>
  </dependencies>
</project>
複製代碼

依賴性排除是如何工做的,以及何時使用它(做爲最後的手段!)

Project-A
   -> Project-B
        -> Project-D <! -- This dependency should be excluded -->
              -> Project-E
              -> Project-F
   -> Project C
複製代碼

從圖中能夠看出,Project-A依賴於Project-B, Project-B依賴於Project-D。Project- D依賴於Project- E和F.默認狀況下,Project A的類路徑包括:

B, C, D, E, F
複製代碼

假設您不但願將項目D及其依賴項添加到項目A的類路徑中,由於存儲庫中缺乏了項目D的一些依賴項,並且您不須要項目b中依賴於項目D的功能。項目b的開發人員能夠將依賴關係標記爲項目d <optional>true</optional>:

<dependency>
  <groupId>sample.ProjectD</groupId>
  <artifactId>ProjectD</artifactId>
  <version>1.0-SNAPSHOT</version>
  <optional>true</optional>
</dependency>
複製代碼

不幸的是,他們沒有。最後,您能夠將其排除在您本身的POM中,用於項目a,以下所示:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>sample.ProjectA</groupId>
  <artifactId>Project-A</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  ...
  <dependencies>
    <dependency>
      <groupId>sample.ProjectB</groupId>
      <artifactId>Project-B</artifactId>
      <version>1.0-SNAPSHOT</version>
      <exclusions>
        <exclusion>
          <groupId>sample.ProjectD</groupId> <!-- Exclude Project-D from Project-B -->
          <artifactId>Project-D</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>
</project>
複製代碼

若是您將Project-A部署到存儲庫中,而且Project-X聲明瞭對Project-A的正常依賴關係,Project-D還會被排除在類路徑以外嗎?

Project-X -> Project-A
複製代碼

答案是確定的。Project-A已經聲明它不須要Project-D來運行,因此它不會做爲Project-A的傳遞依賴項引入。 如今,考慮項目x依賴於項目y,以下圖所示:

Project-X -> Project-Y
               -> Project-B
                    -> Project-D
                       ...
複製代碼

Project-Y也依賴於Project-B,它確實須要Project-D所支持的特性。所以,它不會在依賴項列表中的Project-D上放置排斥。它還可能提供一個額外的存儲庫,從這個存儲庫能夠解析Project-E。在這種狀況下,重要的是不要在全局中排除Project-D,由於它是Project-Y的合法依賴項。

做爲另外一個場景,假設您不想要的依賴項是Project-E而不是Project-D。你如何排除它?見下圖:

Project-A
   -> Project-B
        -> Project-D 
              -> Project-E <!-- Exclude this dependency -->
              -> Project-F
   -> Project C
複製代碼

排除做用做用於聲明它們的點如下的整個依賴關係圖。若是您想排除Project-E而不是Project-D,只需將排除更改成指向Project-E,但不將排除移動到Project-D。您不能更改Project-D的POM。若是能夠,您可使用可選的依賴項而不是排除項,或者將Project-D分割爲多個子項目,每一個子項目只有正常的依賴項。

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>sample.ProjectA</groupId>
  <artifactId>Project-A</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  ...
  <dependencies>
    <dependency>
      <groupId>sample.ProjectB</groupId>
      <artifactId>Project-B</artifactId>
      <version>1.0-SNAPSHOT</version>
      <exclusions>
        <exclusion>
          <groupId>sample.ProjectE</groupId> <!-- Exclude Project-E from Project-B -->
          <artifactId>Project-E</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>
</project>
複製代碼

爲何要在每一個依賴項的基礎上而不是在POM級別上進行排除

這主要是爲了確保依賴關係圖是可預測的,並防止繼承影響排除不該該排除的依賴關係。若是您使用了最後一種方法,而且不得不進行排除,那麼您應該絕對肯定哪些依賴項引入了不須要的傳遞依賴項。

若是您確實但願確保某個特定依賴項不會出如今類路徑中,不管路徑是什麼,均可以將禁止依賴項規則配置爲在發現有問題的依賴項時構建失敗。當構建失敗時,您須要在強制程序找到的每一個路徑上添加特定的排除。

如何在遠程存儲庫中部署jar ?

要將jar部署到外部存儲庫,您必須在pom.xml中配置存儲庫url,並在settings.xml中配置鏈接到存儲庫的身份驗證信息。

下面是一個使用scp和用戶名/密碼身份驗證的例子:

<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>my-app</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.codehaus.plexus</groupId>
      <artifactId>plexus-utils</artifactId>
      <version>1.0.4</version>
    </dependency>
  </dependencies>
 
  <build>
    <filters>
      <filter>src/main/filters/filters.properties</filter>
    </filters>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
  </build>
  <!--
   |
   |
   |
   -->
  <distributionManagement>
    <repository>
      <id>mycompany-repository</id>
      <name>MyCompany Repository</name>
      <url>scp://repository.mycompany.com/repository/maven2</url>
    </repository>
  </distributionManagement>
</project>
複製代碼
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  ...
  <servers>
    <server>
      <id>mycompany-repository</id>
      <username>jvanzyl</username>
      <!-- Default value is ~/.ssh/id_dsa -->
      <privateKey>/path/to/identity</privateKey> (default is ~/.ssh/id_dsa)
      <passphrase>my_key_passphrase</passphrase>
    </server>
  </servers>
  ...
</settings>
複製代碼

注意,若是您正在鏈接到一個openssh ssh服務器的參數「PasswordAuthentication」設置sshd_confing爲"no",你必須輸入你的密碼每次用戶名/密碼身份驗證(儘管您可使用另外一個ssh客戶機登陸輸入用戶名和密碼)。在本例中,您可能但願切換到公鑰身份驗證。 若是在settings.xml中使用密碼,應該當心。有關更多信息,請參見密碼加密。(maven.apache.org/guides/mini…

如何建立文檔?

要開始使用Maven的文檔系統,可使用原型機制使用如下命令爲現有項目生成站點:

mvn archetype:generate \
  -DarchetypeGroupId=org.apache.maven.archetypes \
  -DarchetypeArtifactId=maven-archetype-site \
  -DgroupId=com.mycompany.app \
  -DartifactId=my-app-site
複製代碼

我如何構建其餘類型的項目?

注意,生命週期適用於任何項目類型。例如,回到基本目錄,咱們能夠建立一個簡單的web應用程序:

mvn archetype:generate \
    -DarchetypeGroupId=org.apache.maven.archetypes \
    -DarchetypeArtifactId=maven-archetype-webapp \
    -DgroupId=com.mycompany.app \
    -DartifactId=my-webapp
複製代碼

注意,這些必須都在一行上。這將建立一個名爲my-webapp的目錄,其中包含如下項目描述符:

<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>my-webapp</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
 
  <build>
    <finalName>my-webapp</finalName>
  </build>
</project>
複製代碼

注意<packaging>元素——這告訴Maven將構建爲一個WAR。切換到webapp項目的目錄,並嘗試:

mvn package
複製代碼

你會看到target/my-webapp.war被構建了,全部正常的步驟都被執行了。

如何同時構建多個項目?

Maven內置了處理多個模塊的概念。在本節中,咱們將展現如何構建上面的WAR,並在一個步驟中包含前面的JAR。 首先,咱們須要在前面兩個目錄中添加一個父pom.xml文件,因此它應該是這樣的:

+- pom.xml
+- my-app
| +- pom.xml
| +- src
|   +- main
|     +- java
+- my-webapp
| +- pom.xml
| +- src
|   +- main
|     +- webapp
複製代碼

您將建立的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>
 
  <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>
複製代碼

咱們須要一個從webapp依賴於JAR,因此添加到my-webapp/pom.xml:

...
  <dependencies>
    <dependency>
      <groupId>com.mycompany.app</groupId>
      <artifactId>my-app</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
    ...
  </dependencies>
複製代碼

最後,將如下<parent>元素添加到子目錄中的其餘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">
  <parent>
    <groupId>com.mycompany.app</groupId>
    <artifactId>app</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  ...
複製代碼

如今,試試…從頂層目錄運行:

mvn verify
複製代碼

WAR如今已經在my-webapp/target/my-webapp.war中建立。JAR包括:

$ jar tvf my-webapp/target/my-webapp-1.0-SNAPSHOT.war
   0 Fri Jun 24 10:59:56 EST 2005 META-INF/
 222 Fri Jun 24 10:59:54 EST 2005 META-INF/MANIFEST.MF
   0 Fri Jun 24 10:59:56 EST 2005 META-INF/maven/
   0 Fri Jun 24 10:59:56 EST 2005 META-INF/maven/com.mycompany.app/
   0 Fri Jun 24 10:59:56 EST 2005 META-INF/maven/com.mycompany.app/my-webapp/
3239 Fri Jun 24 10:59:56 EST 2005 META-INF/maven/com.mycompany.app/my-webapp/pom.xml
   0 Fri Jun 24 10:59:56 EST 2005 WEB-INF/
 215 Fri Jun 24 10:59:56 EST 2005 WEB-INF/web.xml
 123 Fri Jun 24 10:59:56 EST 2005 META-INF/maven/com.mycompany.app/my-webapp/pom.properties
  52 Fri Jun 24 10:59:56 EST 2005 index.jsp
   0 Fri Jun 24 10:59:56 EST 2005 WEB-INF/lib/
2713 Fri Jun 24 10:59:56 EST 2005 WEB-INF/lib/my-app-1.0-SNAPSHOT.jar
複製代碼

這是怎麼回事?首先,建立的父POM(稱爲app)有一個pom打包和定義的模塊列表。這告訴Maven在一組項目上運行全部操做,而不是隻運行當前的一個(要覆蓋此行爲,可使用--non-recursive命令行選項)。

接下來,咱們告訴WAR它須要my-app JAR。這作了一些事情:它使WAR中的任何代碼在類路徑上均可用(在本例中沒有),它確保JAR老是在WAR以前構建的,並指示WAR插件將JAR包含在其庫目錄中。

您可能已經注意到junit-4.11.jar是一個依賴項,但最終沒有進入WAR。緣由是<scope>test</scope>元素-它只用於測試,所以不像編譯時依賴my-app那樣包含在web應用程序中。

最後一步是包含父定義。這與Maven 1.0中您可能熟悉的擴展元素不一樣:這確保了即便項目是經過在存儲庫中查找而與父項目單獨分佈的,也始終可以找到POM。

構建生命週期介紹

構建生命週期基礎知識

Maven基於構建生命週期的核心概念。這意味着構建和分發特定工件(項目)的過程被清晰地定義了。

對於構建項目的人員來講,這意味着只須要學習一小組命令就能夠構建任何Maven項目,POM將確保他們獲得他們想要的結果。

有三個內置的構建生命週期:default、clean和site。default生命週期處理項目部署,clean生命週期處理項目清理,而site生命週期處理項目站點文檔的建立。

構建生命週期階段組成

每一個構建生命週期都由不一樣的構建階段列表定義,其中一個構建階段表示生命週期中的一個階段。 例如,默認的生命週期包括如下幾個階段(完整的生命週期階段列表,請參考生命週期參考):

  • validate -驗證項目是正確的,而且全部必要的信息都是可用的
  • compile - 編譯項目的源代碼
  • test - 使用合適的單元測試框架測試編譯後的源代碼。這些測試不該該要求打包或部署代碼
  • package - 將編譯後的代碼以其可分發格式打包,例如JAR。
  • verify - 對集成測試的結果進行任何檢查,以確保知足質量標準
  • install - 將包安裝到本地存儲庫中,以便在本地的其餘項目中做爲依賴項使用
  • deploy - 在構建環境中完成後,將最終的包複製到遠程存儲庫,以便與其餘開發人員和項目共享。

這些生命週期階段(加上這裏沒有顯示的其餘生命週期階段)按順序執行,以完成默認的生命週期。鑑於上面的生命週期階段,這意味着當默認使用生命週期,Maven將首先驗證項目,而後將試圖編譯源代碼,運行這些測試,包二進制文件(如jar),運行集成測試方案,驗證了集成測試,驗證包安裝到本地存儲庫,而後將安裝包部署到遠程存儲庫。

經常使用命令行調用

在開發環境中,使用如下調用將構件構建並安裝到本地存儲庫中。

mvn install
複製代碼

在執行安裝以前,此命令按順序執行每一個默認的生命週期階段(validate, compile, package等)。您只須要調用要執行的最後一個構建階段,在這種狀況下,install: 在構建環境中,使用如下調用乾淨地構建並將構件部署到共享存儲庫中。

mvn clean deploy
複製代碼

同一個命令能夠在多模塊場景中使用(例如,具備一個或多個子項目的項目)。Maven遍歷每一個子項目並執行clean,而後執行deploy(包括全部先前的構建階段步驟)。

構建階段由插件目標組成

然而,即便構建階段負責構建生命週期中的特定步驟,它執行這些職責的方式也可能不一樣。這是經過聲明綁定到那些構建階段的插件目標來實現的。

插件目標表示一個特定的任務(比構建階段更精細),它有助於構建和管理項目。它可能被綁定到零個或多個構建階段。不綁定到任何構建階段的目標能夠經過直接調用在構建生命週期以外執行。執行的順序取決於調用目標和構建階段的順序。例如,考慮下面的命令。clean和package參數是構建階段,而dependency:copy-dependencies是(插件的)目標。

mvn clean dependency:copy-dependencies package
複製代碼

若是這是執行,clean 階段將首先執行(這意味着它將運行全部乾淨的前階段生命週期,加上clean階段自己),而後以dependency:copy-dependencies爲目標,最後執行方案階段(及其構建階段以前的缺省生命週期)。

此外,若是一個目標被綁定到一個或多個構建階段,那麼該目標將在全部這些階段中被調用。 此外,構建階段還能夠有零個或多個目標。若是構建階段沒有綁定目標,那麼該構建階段將不會執行。但若是它有一個或多個目標,它將執行全部這些目標。

設置您的項目以使用構建生命週期

構建生命週期很是簡單,可使用,可是當您爲項目構建Maven構建時,如何爲每一個構建階段分配任務呢?

Packaging

第一種也是最多見的方法是經過一樣命名的POM元素<packaging>設置項目的打包。一些有效的打包值是jar、war、ear和pom。若是沒有指定打包值,則默認爲jar。

每一個包都包含一個要綁定到特定階段的目標列表。例如,jar打包將綁定如下目標來構建默認生命週期的各個階段。

Phase plugin:goal
process-resources resources:resources
compile compiler:compile
process-test-resources resources:testResources
test-compile compiler:testCompile
test surefire:test
package jar:jar
install install:install
deploy deploy:deploy

這幾乎是一組標準的綁定;然而,有些包裝對它們的處理不一樣。例如,一個純元數據的項目(打包值是pom)只將目標綁定到安裝和部署階段(對於一些打包類型的目標到構建階段的完整列表,請參考生命週期引用)。

注意,對於某些可用的打包類型,您可能還須要在POM的<build>部分中包含一個特定的插件,併爲該插件指定<extensions>true</extensions>。叢應用程序和叢服務打包提供了叢應用程序和叢服務打包。

POM文件介紹

什麼是POM

項目對象模型或POM是Maven中的基本工做單元。它是一個XML文件,包含Maven用於構建項目的有關項目和配置細節的信息。它包含大多數項目的默認值。例如build目錄,它是目標;源目錄,即src/main/java;測試源目錄,即src/test/java;等等。在執行任務或目標時,Maven在當前目錄中查找POM。它讀取POM,獲取所需的配置信息,而後執行目標。

POM中能夠指定的一些配置包括項目依賴項、能夠執行的插件或目標、構建概要文件等等。還能夠指定項目版本、描述、開發人員、郵件列表等其餘信息。

Super POM

Super POM是Maven的默認POM。除非顯式設置,不然全部POMs都會繼承Super POM,這意味着在Super POM中指定的配置將由爲項目建立的POMs繼承。下面的代碼片斷是Maven 3.5.4的Super POM。

<project>
  <modelVersion>4.0.0</modelVersion>
 
  <repositories>
    <repository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>
 
  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <releases>
        <updatePolicy>never</updatePolicy>
      </releases>
    </pluginRepository>
  </pluginRepositories>
 
  <build>
    <directory>${project.basedir}/target</directory>
    <outputDirectory>${project.build.directory}/classes</outputDirectory>
    <finalName>${project.artifactId}-${project.version}</finalName>
    <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
    <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
    <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
    <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
    <resources>
      <resource>
        <directory>${project.basedir}/src/main/resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>${project.basedir}/src/test/resources</directory>
      </testResource>
    </testResources>
    <pluginManagement>
      <!-- NOTE: These plugins will be removed from future versions of the super POM -->
      <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.3</version>
        </plugin>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.2-beta-5</version>
        </plugin>
        <plugin>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.8</version>
        </plugin>
        <plugin>
          <artifactId>maven-release-plugin</artifactId>
          <version>2.5.3</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
 
  <reporting>
    <outputDirectory>${project.build.directory}/site</outputDirectory>
  </reporting>
 
  <profiles>
    <!-- NOTE: The release profile will be removed from future versions of the super POM -->
    <profile>
      <id>release-profile</id>
 
      <activation>
        <property>
          <name>performRelease</name>
          <value>true</value>
        </property>
      </activation>
 
      <build>
        <plugins>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-source-plugin</artifactId>
            <executions>
              <execution>
                <id>attach-sources</id>
                <goals>
                  <goal>jar-no-fork</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-javadoc-plugin</artifactId>
            <executions>
              <execution>
                <id>attach-javadocs</id>
                <goals>
                  <goal>jar</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-deploy-plugin</artifactId>
            <configuration>
              <updateReleaseInfo>true</updateReleaseInfo>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>
 
</project>
複製代碼
相關文章
相關標籤/搜索