1. 程式人生 > 程式設計 >Maven介紹

Maven介紹

什麼是Maven

乍一看,Maven似乎包含很多內容,但簡而言之,Maven試圖將模式應用於專案的構建基礎設施,以便通過提供使用最佳實踐的清晰路徑來促進理解和生產力。Maven本質上是一個專案管理和理解工具,因此提供了一種幫助管理的方法:

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

歷史

Maven最初設計,是以簡化Jakarta Turbine專案的建設。在幾個專案,每個專案包含了不同的Ant構建檔案。 JAR檢查到CVS。

目標

1)為了使專案管理更加簡單。

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

3)提供優質專案的資訊。

4)為最佳實踐開發提供指導。

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

建立

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
複製程式碼

結果:

 ...
[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版本(例如9、10、11、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,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,Time elapsed: 0.001 sec
 
Results :
[surefire] Tests run: 1,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>
複製程式碼