介紹maven構建的生命周期
這篇是 https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html 的譯文。
構建生命周期的基礎知識
構建的生命周期是maven的最核心概念。它的意思就是構建和發布某個特定的artifact(project)的每個階段是否清晰定義。
對想要構建一個project的開發人員來說,只需要掌握非常少的命令,就可以編譯一個maven的項目,pom會保證會生成我們希望的產出結果。
有三個內置的構建周期:default,clean 和site。default周期處理項目的部署。clean周期處理項目的清理。site周期創建項目的站點文檔。
構建的生命周期由階段組成
每個生命周期都由一些不同的構建階段組成。每個構建階段都是生命周期的一個步驟。
例如,default生命周期由下面的階段組成:
- validate - 驗證項目是否正確,並且所有必要的信息是否有效
- compile - 編譯項目的代碼
- test - 使用合適的單元測試框架測試源碼。這些測試代碼並不要求打包或者部署
- package - 獲取編譯后的代碼,並且把它們打成可派發的格式,比如JAR.
- verify - 運行集成測試,以確保項目符合質量標准
- install - 安裝包到本地的repository中,以便其他項目可以依賴這個項目。
- deploy - 在構建的結束階段,把最終包上傳到遠端的repository中,以便其他的項目和開發者可以使用。
這些構建周期的各個步驟是用來順序執行,以便完成default的生命周期。(當然其他的生命周期的步驟還沒有介紹)。這就意味着,一旦使用了default生命周期,maven會首先驗證項目,然后編譯代碼,跑單元測試,打包二進制文件,運行集成測試,驗證集成測試,安裝驗證后的包到本地倉庫,然后部署到遠端倉庫。
使用命令行調用
在開發環境,使用下面的命令構建和安裝項目到本地倉庫
mvn install
這個命令執行default生命周期中install階段及之前的階段(比如validate,compile,package等)。就是說,你只需要調用最后一個需要你執行的階段就能執行這個階段之前的命令了。
在構建環境,使用下面的命令就能清空構建發布在共享倉庫中的項目。
mvn clean deploy
在多模塊場景,maven進入到每個子項目並且執行clean,然后執行deploy。
一個構建的過程是由插件的目標組成
雖然一個構建過程是為構建生命周期的某個階段負責,但是,實現這個階段的方法有多種多樣。這些方法是由綁定再這些編譯階段的插件的目標來實現的。
一個插件的目標代表一個用於構建和管理項目的任務(任務的概念比構建過程更為精細)。一個任務可以被綁定在零個或者多個構建過程上。沒有被綁定在任何構建過程的目標也可以被直接調用。執行的順序由目標和構建過程調用的順序來定。例如,下面的命令。clean和package是構建過程,dependency:copy-dependencies是一個插件的目標。
mvn clean dependency:copy-dependencies package
執行這個命令,clean構建過程會被執行(意味着它執行clean構建過程之前的所有過程),然后dependency:copy-dependencies目標會被執行,最后,執行package構建過程(及前面所有的構建過程)。
如果一個目標綁定在一個或者多個構建階段,這個目標會被所有構建階段調用。
換句話說,一個構建階段可以由零個或者多個目標綁定。如果一個構建階段沒有目標綁定,那么這個構建階段就不會執行。但是一旦有一個或者多個目標綁定,它就會執行這些目標。
(注意:在Maven 2.0.5及之上,一個構建階段的多個目標的執行順序,是和這些目標在POM中聲明的順序一致的。但是,多個相同的插件是不允許的。在Maven2.0.11及以上版本,要是定義了多個相同插件,他們會被分組並且一起執行。)
一些構建階段一般不會通過命令行進行調用
一些由復合詞(pre-*, post-*, process-*)組成的構建階段通常不會由命令行直接調用。這些構建過程連接整個構建流程,產生不被外部使用的中間結果。例如調用integration-test階段,整個環境會停留在懸掛狀態。
代碼覆蓋工具,例如Jacoco,執行容器插件,例如Tomcat,Cargo和Docker把目標綁定在pre-integration-test階段,用於准備測試的容器環境。這些插件也綁定在post-integration-test階段,用於收集覆蓋率的統計,或者回收測試容器。
故障保護和代碼覆蓋插件綁定目標在integration-test和verify階段。最終的結果就是在verify階段之后生成可用的測試和代碼覆蓋率報告。如果integration-test由命令行調用,就不會生成任何的報告。更糟糕的是,遷移測試的容器環境就會停留在懸掛狀態。Tomcat服務和Docker實例就會一直運行,maven不會自己終止。
使用構建生命周期來搭建項目
構建的生命周期是很容易使用的。但是具體當我們考慮使用maven構建一個項目的時候,如何為每個構建過程指定任務呢?
Packaging
首先,最通用的方法,通過POM中的
每個packaging會由一些特定的目標綁定在特定的任務中,比如,jar打包方式會綁定下面的目標在默認的生命周期中。
上圖差不多就是基本的綁定設置。但是一些打包方式是不一樣的設置。例如,純元項目的打包方式(pom)只綁定了install和deploy構建階段。
注意,除了默認的,一些額外的打包方式也是可以額外獲取。你可以使用pom文件的
Plugins
第二種把目標增加到構建階段的方法是在你的項目中配置插件。插件就是提供目標給maven的項目。或者說,插件可以有一個或者多個目標,每個目標代表插件的一種能力。例如,Compiler插件有兩個目標:compile和testCompile。前者編譯你的主代碼,后者編譯你的測試代碼。
在后面的章節你會看到,插件包含希望在什么構建階段插入目標的信息。注意,插件自己並沒有這個信息-你必須指定你想要在哪個編譯階段使用這個目標。
目標可以配置到那些已經被Packaging綁定的構建階段中。如果多個目標綁定到一個特定階段,執行的順序是,先執行packaging中的目標,再執行配置文件POM配置的目標。注意,你可以通過
例如,Modello插件會將modello:java目標綁定到generate-source階段(注意:modello:java目標會生成java代碼)。所以,使用Modello插件並且讓它生成代碼並且將代碼加入到build階段,你需要加下面的
...
<plugin>
<groupId>org.codehaus.modello</groupId>
<artifactId>modello-maven-plugin</artifactId>
<version>1.8.1</version>
<executions>
<execution>
<configuration>
<models>
<model>src/main/mdo/maven.mdo</model>
</models>
<version>4.0.0</version>
</configuration>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
</plugin>
...
你也許會很好奇為什么
當多個executions被配置給一個單獨的過程,它們會按照POM中配置的
例如,modello:java,它只在generate-source構建階段生效。但是一些目標卻會在一個或者多個構建階段執行,並且這些目標並不強制要求按照默認階段執行。對這些,你就需要自己來配置了。例如,你有一個目標display:time,這個目標是打印當前時間到控制台,如果你希望它在process-test-resources階段執行,以便告知什么時候測試開始執行,你就需要配置如下:
...
<plugin>
<groupId>com.mycompany.example</groupId>
<artifactId>display-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>process-test-resources</phase>
<goals>
<goal>time</goal>
</goals>
</execution>
</executions>
</plugin>
...
生命周期相關參考
下面是default, clean 和site生命周期的所有構建階段,按照下文所示的順序執行。
clean生命周期
- pre-clean: execute processes needed prior to the actual project cleaning
- clean: remove all files generated by the previous build
- post-clean: execute processes needed to finalize the project cleaning
default生命周期
- validate: validate the project is correct and all necessary information is available.
- initialize: initialize build state, e.g. set properties or create directories.
- generate-sources: generate any source code for inclusion in compilation.
- process-sources: process the source code, for example to filter any values.
- generate-resources: generate resources for inclusion in the package.
- process-resources: copy and process the resources into the destination directory, ready for packaging.
- compile: compile the source code of the project.
- process-classes: post-process the generated files from compilation, for example to do bytecode enhancement on Java classes.
- generate-test-sources: generate any test source code for inclusion in compilation.
- process-test-sources: process the test source code, for example to filter any values.
- generate-test-resources: create resources for testing.
- process-test-resources: copy and process the resources into the test destination directory.
- test-compile: compile the test source code into the test destination directory
- process-test-classes: post-process the generated files from test compilation, for example to do bytecode enhancement on Java classes. For Maven 2.0.5 and above.
- test: run tests using a suitable unit testing framework. These tests should not require the code be packaged or deployed.
- prepare-package: perform any operations necessary to prepare a package before the actual packaging. This often results in an unpacked, processed version of the package. (Maven 2.1 and above)
- package: take the compiled code and package it in its distributable format, such as a JAR.
- pre-integration-test: perform actions required before integration tests are executed. This may involve things such as setting up the required environment.
- integration-test: process and deploy the package if necessary into an environment where integration tests can be run.
- post-integration-test: perform actions required after integration tests have been executed. This may including cleaning up the environment.
- verify: run any checks to verify the package is valid and meets quality criteria.
- install: install the package into the local repository, for use as a dependency in other projects locally.
- deploy: done in an integration or release environment, copies the final package to the remote repository for sharing with other developers and projects.
site生命周期
- pre-site: execute processes needed prior to the actual project site generation
- site: generate the project's site documentation
- post-site: execute processes needed to finalize the site generation, and to prepare for site deployment
- site-deploy: deploy the generated site documentation to the specified web server
內置的生命周期綁定目標
一些生命周期已經綁定了一些目標。這些默認的生命周期,依賴packaging值不同有不同的目標。下面是一些構建階段的目標:
Clean 生命周期綁定
Default 生命周期 - Packaging值為 ejb / ejb3 / jar / par / rar / war
Default 生命周期 - Packaging值為 ear
Default 生命周期 - Packaging值為 maven-plugin
Default 生命周期 - Packaging值為 pom
Site 生命周期綁定
參考
完整的Maven生命周期是在maven-core模塊的components.xml文件中定義,相關查看文檔。
Maven2.x中,默認的生命周期綁定的目標描述是在components.xml,但在Maven3.x中,是在單獨的default-bindings.xml 文件中配置的。