生命週期

之前外掛一節提過,plugin提供了各種Goal來達成各自的目的,像之前提過的

mvn clean:clean package javadoc:javadoc

等等,怎麼找不到 package 是哪個Goal?

您是否想過打包Jar、EJB或Web,它們的目錄結構會是一樣的嗎?

沒有一種打包的外掛能夠Cover各種不同的打包,也許您也會像spring-boot-maven-plugin自行開發打包的方式。

想想package這件事,至少要經過拷貝資源、編譯程式、測試等階段(Phase),才會開始打包吧!

所以我們知道Phase是包含從開始到標的Goal的一系列集合。

而Maven所謂的生命週期(LifeCycle)就是指一連串的 Phase 所形成。

Maven有三種不同的生命週期,我們先來看一下官方所列出的表格

Phase以打包Jar的 plugin:goal說明
process-resourcesresources:resourcessrc/main/resources(也許先過濾)拷貝到 classes 目錄
compilecompiler:compile編譯main/src源碼
process-test-resourcesresources:testResourcessrc/test/resources(也許先過濾)拷貝到 target/test-classes 目錄
test-compilecompiler:testCompile編譯src/main/java源碼
testsurefire:test進行單元測試
packagejar:jar把專案打包成Jar檔
installinstall:install把Jar檔安裝到本機函式庫(之前在專案管理一節使用過install:install-file)
deploydeploy:deploy把Jar檔發佈到遠端函式庫(例如Maven的中央庫)

從上表看,我們package一個Jar檔時,不止是執行jar:jar這個Goal,而是在package這個Phase之前的Phase都要依序執行過, 這也是為什麼我們只要執行package時,未compile過的程式能被編譯的關鍵 。

當需要執行phase時,Maven會執行該phase所關聯的Goal,這也是spring-boot-maven-plugin能夠在package時進行打包。

記得在直接執行程式一節我們透過指令直接執行程式

mvn compile exec:java

exec:java是一個獨立的Goal,所以我們要在執行之前要先確保程式經過compile,所以要串接兩個指令, 現在我只要指定在test這個phase執行這個Goal,就可以不用這麼麻煩了。

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>exec-maven-plugin</artifactId>
  <version>3.1.1</version>
  <executions>
    <execution><!--設定Goal的執行方式-->
      <phase>test</phase><!--在test pahse時執行下列的Goal-->
      <goals>
        <goal>java</goal> <!--要執行的goal-->
      </goals>
    </execution>
  </executions>
  <configuration>
    <mainClass>${exec.mainClass}</mainClass>
    <cleanupDaemonThreads>false</cleanupDaemonThreads>
  </configuration>
</plugin>

現在我們只要直接執行 mvn test ,Maven就會執行test phase之前所有的pahse,我們就可以不用考慮源碼的編譯問題。

之前我們提到過Maven有三大生命周期,包括clean(清理目錄結構)、build(上面的package表格只是這個的一部份)、與 site(主管文件產製)。 強烈建議要查看官方文件

打開官方文件,瞭解生命周期有哪些phases外,再對照各個pahse關聯(Binding)的Goal,至此,便可算Maven入了門。

我要特別提一下Default Lifecycle最後有四個phases值得注意:

Phase說明
pre-integration-test整合測試前
integration-test整合測試
post-integration-test整合測試後
verify運行任何檢查以驗證打包是否有效並符合品質標準

一般來說單元測試只是針對函式做輸入輸出的驗證,而整合測試則是包含實際的運作(可能測試是有時間序的,比如登錄後才能測試功能), 前一小節直接執行程式有提過如何讓Web專案直接潤(run)起來。

再配上上面所說的<executions>,我們根本可以在整合測試前,讓Jetty Web執行後再進行整合測試,然後測試完成後,再關閉Jetty Web。

<plugin>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <version>11.0.20</version>
  <executions>
    <execution>
      <id>start-jetty</id>
      <phase>pre-integration-test</phase>
      <goals>
        <goal>start</goal>
      </goals>
    </execution>
    <execution>
      <id>stop-jetty</id>
      <phase>post-integration-test</phase>
      <goals>
        <goal>stop</goal>
      </goals>
    </execution>
  </executions>
</plugin>

註1:整合測試需要用到Maven Failsafe Plugin,版本通常與maven-surefire-plugin一致。

註2:Maven 的 Goal 可會有預設綁定(default bind)的phase,如果<execution>未指定<phase>時,則依預設binding phase執行。

例如我們沒有特別編譯就直可直接執行 mvn jetty:run 是因為 jetty 執行前確保會執行 compile。

可以執行 mvn org.eclipse.jetty:jetty-maven-plugin:help -Dgoal=run 看一下說明。