天天看點

Maven介紹什麼是Maven快速開始建構生命周期介紹POM檔案介紹

Maven介紹

  • 什麼是Maven
    • 曆史
    • 目标
    • 建立
      • 建立一個工程
      • 編譯jar包
      • Java9或者之後的版本
    • Maven階段
  • 快速開始
    • 建立工程
    • 編譯Maven
    • 我如何編譯我的測試源并運作我的單元測試?
    • 如何建立一個JAR并将其安裝到本地存儲庫中?
    • 什麼是快照版本?
    • 我如何使用插件?
    • 如何向JAR添加資源?
    • 如何過濾資源檔案?
    • 我如何使用外部依賴?
      • 依賴傳遞
      • 依賴範圍
      • 依賴管理
      • 引入依賴項
      • 系統依賴
    • Optional & Exclusion
      • 可選依賴關系
        • 為什麼使用可選依賴項?
        • 如何使用optional标簽
        • 可選依賴項如何工作?
        • 例子
      • Dependency Exclusions
        • 如何使用dependency exclusions
        • 依賴性排除是如何工作的,以及什麼時候使用它(作為最後的手段!)
        • 為什麼要在每個依賴項的基礎上而不是在POM級别上進行排除
    • 如何在遠端存儲庫中部署jar ?
    • 如何建立文檔?
    • 我如何建構其他類型的項目?
    • 如何同時建構多個項目?
  • 建構生命周期介紹
    • 建構生命周期基礎知識
    • 建構生命周期階段組成
      • 常用指令行調用
      • 建構階段由插件目标組成
    • 設定您的項目以使用建構生命周期
      • Packaging
  • POM檔案介紹
    • 什麼是POM
    • Super POM

什麼是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, 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檔案的(稍後我們将對此進行更多讨論)。現在可以檢視 b a s e d i r / t a r g e t 目 錄 , 您 将 看 到 生 成 的 J A R 文 件 。 現 在 , 您 将 希 望 将 生 成 的 工 件 ( J A R 文 件 ) 安 裝 到 本 地 存 儲 庫 ( {basedir}/target目錄,您将看到生成的JAR檔案。 現在,您将希望将生成的工件(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

  • **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中。

您可以在下面的示例中看到,我們添加了 b a s e d i r / s r c / m a i n / r e s o u r c e s 目 錄 , 将 希 望 打 包 到 J A R 中 的 任 何 資 源 放 入 其 中 。 M a v e n 使 用 的 簡 單 規 則 是 : {basedir}/src/main/resources目錄,将希望打包到JAR中的任何資源放入其中。Maven使用的簡單規則是: 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.xml

pom.properties

檔案。這些都是Maven中生成JAR的标準配置。如果您選擇,您可以建立自己的清單,但是Maven将在預設情況下生成清單。(您還可以修改預設清單中的條目。這個我們以後再談。)

pom.xml

pom.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

,

resources

resource

元素。此外,我們必須顯式地聲明資源位于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元素訓示項目如何使用該依賴項,可以是

compile

test

runtime

等值。有關可以為依賴項指定的所有内容的更多資訊,請參見項目描述符引用(https://maven.apache.org/ref/3.6.1/maven-model/maven.html)。

有了這些關于依賴項的資訊,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

,

system

provided

。用于計算用于編譯、測試等的各種類路徑。它還幫助确定在這個項目的發行版中包含哪些工件。有關更多資訊,請參見依賴機制。預設範圍是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中使用密碼,應該小心。有關更多資訊,請參見密碼加密。(https://maven.apache.org/guides/mini/guide-encryption.html)

如何建立文檔?

要開始使用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

等)。您隻需要調用要執行的最後一個建構階段,在這種情況下,

instal

l:

在建構環境中,使用以下調用幹淨地建構并将構件部署到共享存儲庫中。

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>
           

繼續閱讀