The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

深入淺出 Apache Maven 的 Plugins 外掛機制

Apache Maven 之所以強大,是因為他有一個強大的 Plugin 執行框架,你任何想讓 Maven 幫你完成的工作,無論是建置(Build)、封裝(Packaging)、產生報表(Reporting)、執行測試(Tests),全部都是透過 Plugins 完成的。它除了內建的核心 Plugins 之外,還有數以百計的第三方 Plugins 可以安裝使用。今天這篇文章我就來介紹一下他的基本架構與使用方式。

簡介 Apache Maven Plugins

基本上 Apache Maven 的 Plugins 分成兩大類,並且可以定義在專案的 pom.xml 檔案中:

  1. 建置外掛 (Build plugins)

    用來執行在建置(build)過程中的所有大小事,他會定義在 POM 檔的 <build/> 元素底下。

  2. 報表外掛 (Reporting plugins)

    用來執行在建立文件網站(site)過程中的所有大小事,他會定義在 POM 檔的 <reporting/> 元素底下。

    由於報表外掛(Reporting plugins)的結果會被發佈在文件網站(site)上,所以必須考量多國語系(internationalized)與本地化(localized)的要求。詳見 Localization of Plugins 說明。

Apache Maven 官方支援許多 Plugins,並且詳細列在 Available Plugins 頁面中,光是這些內建的 Plugins 就可以幫我們解決 95% 以上的建置或報表工作,真的相當厲害且富有內涵,我很難在一篇文章內介紹這麼多 Plugins,只能淺淺帶過,有興趣大家可以個別研究不同的 Plugins。

突然覺得可以所有 Plugins 都介紹的話,那就可以參加 2022 iThome 鐵人賽 了吧!😅

以下我就列出這些官方支援的 Plugins 清單,大家可以看的大概,有點印象即可:

  • 核心外掛 (Core plugins)

    Plugin 類型 摘要說明
    compiler 建置 Compiles Java sources.
    deploy 建置 Deploy the built artifact to the remote repository.
    failsafe 建置 Run the JUnit integration tests in an isolated classloader.
    install 建置 Install the built artifact into the local repository.
    resources 建置 Copy the resources to the output directory for including in the JAR.
    site 建置 Generate a site for the current project.
    surefire 建置 Run the JUnit unit tests in an isolated classloader.
    verifier 建置 Useful for integration tests - verifies the existence of certain conditions.
    clean 建置 Clean up after the build.
  • 封裝外掛 (Packaging types/tools)

    Plugin 類型 摘要說明
    jar 建置 Build a JAR (Java ARchive) from the current project.
    war 建置 Build a WAR (Web Application Archive) from the current project.
    ear 建置 Generate an EAR (Enterprise ARchive) from the current project.
    ejb 建置 Build an EJB (and optional client) from the current project.
    rar 建置 Build a RAR (Resource Adapter Archive) from the current project.
    app-client/acr 建置 Build a JavaEE application client from the current project.
    shade 建置 Build an Uber-JAR from the current project, including dependencies.
    source 建置 Build a source-JAR from the current project.
    jlink 建置 Build Java Run Time Image.
    jmod 建置 Build Java JMod files.
  • 報表外掛 (Reporting plugins)

    Plugin 類型 摘要說明
    changelog 報表 Generate a list of recent changes from your SCM.
    changes 建置+報表 Generate a report from an issue tracker or a change document.
    checkstyle 建置+報表 Generate a Checkstyle report.
    doap 建置 Generate a Description of a Project (DOAP) file from a POM.
    docck 建置 Documentation checker plugin.
    javadoc 建置+報表 Generate Javadoc for the project.
    jdeps 建置 Run JDK's JDeps tool on the project.
    jxr 建置 Generate a source cross reference.
    linkcheck 建置 Generate a Linkcheck report of your project's documentation.
    pmd 建置+報表 Generate a PMD report.
    project-info-reports 報表 Generate standard project reports.
    surefire-report 報表 Generate a report based on the results of unit tests.
  • 工具外掛 (Tools)

    Plugin 類型 Description
    antrun 建置 Run a set of ant tasks from a phase of the build.
    artifact 建置 Manage artifacts tasks like buildinfo.
    archetype 建置 Generate a skeleton project structure from an archetype.
    assembly 建置 Build an assembly (distribution) of sources and/or binaries.
    dependency 建置+報表 Dependency manipulation (copy, unpack) and analysis.
    enforcer 建置 Environmental constraint checking (Maven Version, JDK etc), User Custom Rule Execution.
    gpg 建置 Create signatures for the artifacts and poms.
    help 建置 Get information about the working environment for the project.
    invoker 建置+報表 Run a set of Maven projects and verify the output.
    jarsigner 建置 Signs or verifies project artifacts.
    jdeprscan 建置 Run JDK's JDeprScan tool on the project.
    patch 建置 Use the gnu patch tool to apply patch files to source code.
    pdf 建置 Generate a PDF version of your project's documentation.
    plugin 建置+報表 Create a Maven plugin descriptor for any mojos found in the source tree, to include in the JAR.
    release 建置 Release the current project - updating the POM and tagging in the SCM.
    remote-resources 建置 Copy remote resources to the output directory for inclusion in the artifact.
    scm 建置 Execute SCM commands for the current project.
    scm-publish 建置 Publish your Maven website to a scm location.
    scripting 建置 The Maven Scripting Plugin wraps the Scripting API according to JSR223.
    stage 建置 Assists with release staging and promotion.
    toolchains 建置 Allows to share configuration across plugins.
    wrapper 建置 Download and unpack the maven wrapper distribution

除了 Maven 官方支持的 Plugins 外,還有個 MojoHaus Maven Plugins Project 由社群維護了一系列好用的 Plugins,有空的時候去翻看看,搞不好有意外之喜。在這個 MojoHaus 的世界裡所稱呼的 Mojo (Maven plain Old Java Object) 通常是指 Plugin 中的某個 Goal 實作,很多 Plugin 的 Goal 在實作的時候也會以 ___Mojo 結尾,來當成 Goal 的方法名稱,是一種 Maven plugins 常見的命名規則。我們其實經常會在許多文件中看到這個單字,而這個 Mojo 單字有「魔力」、「魅力」等含意!

認識 Maven 的建置生命週期(lifecycle)、階段(phase)與目標(goal)

在 Maven 裡面有許多「抽象概念」經常會混淆著初學者,因為你只要沒有認真看懂這些概念,根本就無法好好的使用 Maven 這套優異的建置工具。

首先,你要先知道 Maven 定義了三種不同的生命週期,彼此相關而不重複:

  1. default

    處理專案的建置(build)與部署(deployment)等工作

  2. clean

    處理專案的清理工作,將建置過程中產生的檔案清除

  3. site

    處理專案文件網站的產生工作

你從官網的 Lifecycles Reference 文件可以發現,每個不同的生命週期(lifecycle)分別定義了一系列依序執行的階段(phase),這些階段是 Maven 依據過往數十年的最佳實務整理出來的寶貴經驗。

請注意,這些所謂的「生命週期」與「階段」都只是個「概念」而已,所代表意義是:

  1. 當你想要建置部署時 (default),你必須依據 Maven 所定義的階段來執行任務

    <phases>
      <phase>validate</phase>
      <phase>initialize</phase>
      <phase>generate-sources</phase>
      <phase>process-sources</phase>
      <phase>generate-resources</phase>
      <phase>process-resources</phase>
      <phase>compile</phase>
      <phase>process-classes</phase>
      <phase>generate-test-sources</phase>
      <phase>process-test-sources</phase>
      <phase>generate-test-resources</phase>
      <phase>process-test-resources</phase>
      <phase>test-compile</phase>
      <phase>process-test-classes</phase>
      <phase>test</phase>
      <phase>prepare-package</phase>
      <phase>package</phase>
      <phase>pre-integration-test</phase>
      <phase>integration-test</phase>
      <phase>post-integration-test</phase>
      <phase>verify</phase>
      <phase>install</phase>
      <phase>deploy</phase>
    </phases>
    
  2. 當你想要清理時 (clean),你必須依據 Maven 所定義的階段來執行任務

    <phases>
      <phase>pre-clean</phase>
      <phase>clean</phase>
      <phase>post-clean</phase>
    </phases>
    <default-phases>
      <clean>
        org.apache.maven.plugins:maven-clean-plugin:2.5:clean
      </clean>
    </default-phases>
    
  3. 當你想要建立文件網站時 (site),你必須依據 Maven 所定義的階段來執行任務

    <phases>
      <phase>pre-site</phase>
      <phase>site</phase>
      <phase>post-site</phase>
      <phase>site-deploy</phase>
    </phases>
    <default-phases>
      <site>
        org.apache.maven.plugins:maven-site-plugin:3.3:site
      </site>
      <site-deploy>
        org.apache.maven.plugins:maven-site-plugin:3.3:deploy
      </site-deploy>
    </default-phases>
    

請注意: 所有的階段(phase)其名稱都是不重複的。

瞭解了這些生命週期階段的概念之後,你就必須知道,所有的 Java 專案都可以依據實際的需求來定義特定階段(phase)要執行什麼樣的目標(goal)!

所以,生命週期(lifecycle)與階段(phase)就只是個概念(Concepts),而目標(goal)才是你真正要做的事情 (要達成的目標)!

我用一個非常簡單的例子來說明:

  1. 我們用以下命令建立一個全新的 Java 專案

    mvn archetype:generate -B `
      '-DarchetypeCatalog=internal' `
      '-DgroupId=com.duotify' `
      '-DartifactId=demo1' `
      '-Dversion=1.0-SNAPSHOT'
    

    由於 Maven 預設會採用 org.apache.maven.archetypes:maven-archetype-quickstart:1.0 這個專案範本(archetype),所以不用寫底下這段較長的命令:

    mvn archetype:generate -B `
      '-DarchetypeCatalog=internal' `
      '-DgroupId=com.duotify' `
      '-DartifactId=demo1' `
      '-Dversion=1.0-SNAPSHOT' `
      '-DarchetypeGroupId=org.apache.maven.archetypes' `
      '-DarchetypeArtifactId=maven-archetype-quickstart' `
      '-DarchetypeVersion=1.0'
    

    這只是一個非常簡單的 Console 專案:

    image

    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/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.duotify</groupId>
      <artifactId>demo1</artifactId>
      <packaging>jar</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>demo1</name>
      <url>http://maven.apache.org</url>
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </project>
    
  2. 然後我們直接執行 mvn 命令,並獲取以下錯誤訊息

    [INFO] Total time:  0.133 s
    [INFO] Finished at: 2022-09-11T18:04:06+08:00
    [INFO] ------------------------------------------------------------------------
    [ERROR] No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]
    [ERROR]
    [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
    [ERROR] Re-run Maven using the -X switch to enable full debug logging.
    [ERROR]
    [ERROR] For more information about the errors and possible solutions, please read the following articles:
    [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/NoGoalSpecifiedException
    

    這裡的重點在這段:

    No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy.

    這段英文應該不難理解,你必須在 mvn 命令後面指定一個 phasegoal 才能執行 Maven!

  3. 假設我們只要編譯目前的專案,那我們可以指定 compile 這個階段

    mvn compile
    

    上述命令執行時會掛掉,容後補充說明。

    由於這個 compile 階段隸屬於 default 生命週期,因此 Maven 就會從 default 生命週期的第一個 phase 開始找尋是否有相對應的目標(goal)需要達成。

    所以 Maven 會依序去查找 validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile 這幾個階段是否有相對應的目標(goal)去執行程式。

    基本上,整個 Maven 就是這樣跑起來的!👍

此時重點就要登場了,所以我們所說的目標(goal)具體來說到底是什麼呢?

理解 Plugin 與 Goal 之間的關係

事實上,我們註冊到 pom.xml 的每一個 Plugins,裡面分別都「實作」了一個到多個目標(goals),而這些 Plugin 裡面的目標(goals)會明確綁定到特定階段(phase),當 Maven 執行到該階段(phase)的時候,就會自動執行這個 Plugin 的目標(goal)。說穿了,所謂的目標(goal)就是一個類別中的方法而已。

一般來說,在 Plugin 裡面的目標名稱(goal name)經常會跟階段名稱(phase name)刻意設計的一樣,這樣也比較好辨識,但這並不是必要條件。

我以 Apache Maven Compiler Plugin 為例,這個 Plugin 實作了 3 個目標

  1. compiler:compile

    用來綁定 compile phase 並用來編譯 Java 主程式的原始碼(src/main/**)。

  2. compiler:testCompile

    用來綁定 test-compile phase 並用來編譯 Java 測試程式的原始碼(src/test/**)。

  3. compiler:help

    用來顯示這個 compiler plugin 的使用說明。

    幾乎所有 Plugin 都會實作 help 這個目標(goal),方便開發人員查詢相關用法。你可以執行 mvn compiler:help 查詢相關用法。

有趣的地方在於,在官網的 Plugin Documentation 文件中,並沒有明確跟你說這些 Goal 要怎樣使用、用在哪裡,這些細節已經被定義在 Maven 的生命週期(lifecycle)、階段(phase)與目標(goal)之中了。因此你若沒有先建立好完整且清晰的概念,就會無法理解 Maven 的運作原理。

我們接續上一段的例子,當我們執行 mvn compile 命令的時候,實際上完整的流程如下:

  1. 先選中 compile 階段(phase),藉此判斷出 default 這個生命週期(lifecycle)

  2. 依序執行 default 生命週期(lifecycle)的每個階段(phase)

    1. 找尋所有 Plugins 中是否有實作綁定任何名稱為 validate 階段(phase)的目標(goal)
    2. 找尋所有 Plugins 中是否有實作綁定任何名稱為 initialize 階段(phase)的目標(goal)
    3. 找尋所有 Plugins 中是否有實作綁定任何名稱為 generate-sources 階段(phase)的目標(goal)
    4. 找尋所有 Plugins 中是否有實作綁定任何名稱為 process-sources 階段(phase)的目標(goal)
    5. 找尋所有 Plugins 中是否有實作綁定任何名稱為 generate-resources 階段(phase)的目標(goal)
    6. 找尋所有 Plugins 中是否有實作綁定任何名稱為 process-resources 階段(phase)的目標(goal)
    7. 找尋所有 Plugins 中是否有實作綁定任何名稱為 compile 階段(phase)的目標(goal)

如此一來 mvn compile 命令便執行完畢!

由於 compile plugin 是 Maven 的核心 plugins 之一,所以預設就會註冊在 pom.xml 之中,不用特別設定,而上述過程只有 compile 這個目標(goal)有被比對中,因此到 compile 這個階段(phase)的時候,就會跑去執行 compile:compile 目標(goal)。

如果我直接執行 mvn compile:compile 的話,就代表我們執行的是 compile 這個 plugin 的 compile 目標而已,不會去執行其他階段(phase),因此也不會去執行其他 Plugins 中的任何目標。

所以 mvn compilemvn compile:compile 所代表的意義是截然不同的!

解決無法編譯的問題

我先前有提到,這個範例專案其實無法編譯,你在執行 mvn compile 的時候會發現以下訊息:

[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------< com.duotify:demo1 >--------------------------
[INFO] Building demo1 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ demo1 ---
[WARNING] Using platform encoding (MS950 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory G:\Projects\demo1\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ demo1 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding MS950, i.e. build is platform dependent!
[INFO] Compiling 1 source file to G:\Projects\demo1\target\classes
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] Source option 5 is no longer supported. Use 7 or later.
[ERROR] Target option 5 is no longer supported. Use 7 or later.
[INFO] 2 errors
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.991 s
G:\Projects\demo1>mvn compile:compile
[INFO] Scanning for projects...
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-metadata.xml
Downloading from central: https://repo.maven.apache.org/maven2/org/codehaus/mojo/maven-metadata.xml
Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-metadata.xml (14 kB at 14 kB/s)
Downloaded from central: https://repo.maven.apache.org/maven2/org/codehaus/mojo/maven-metadata.xml (21 kB at 21 kB/s)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.733 s
[INFO] Finished at: 2022-09-11T18:40:45+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] No plugin found for prefix 'compile' in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories [local (C:\Users\wakau\.m2\repository), central (https://repo.maven.apache.org/maven2)] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/NoPluginFoundForPrefixException

你可以從上述訊息得知,其實這個 mvn compile 在執行的過程中,執行了 2 個目標:

  1. maven-resources-plugin:2.6:resources
  2. maven-compiler-plugin:3.1:compile

而在執行 maven-compiler-plugin:3.1:compile 目標時,卻發生了以下錯誤:

[ERROR] Source option 5 is no longer supported. Use 7 or later.
[ERROR] Target option 5 is no longer supported. Use 7 or later.

首先,看起來 Maven 內建的 maven-compiler-plugin 選用了 3.1 版本有點過於老舊,他預設使用 Java 5 來編譯原始碼,但我的電腦裝的是 JDK 17,編譯器最低支援版本從 Java 7 開始支援,所以才會編譯失敗。

要解決這個問題其實很簡單,只要在專案的 pom.xml 加入這個 maven-compiler-plugin plugin 並提供選項設定即可。

我打算加入以下 XML 片段到 pom.xml 檔案中,藉此指定最新版的 maven-compiler-plugin plugin:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.10.1</version>
      </plugin>
    </plugins>
  </build>
  ...
</project>

再重新執行一次 mvn compile 就會發現專案已經可以成功建置!

其實為了讓建置過程可以更穩定,一般來說我們會明確指定各個 Plugins 的版本資訊(<version>3.10.1</version>),否則當 Plugin 版本變化時,若是遇到破壞性更新(Breaking changes)那就遭了!

image

除了指定 maven-compiler-plugin plugin 到最新版本外,你也可以透過 plugin 的 <configuration> 來指定參數,讓 maven-compiler-plugin 可以選用 1.7 當成我們的原始碼版本,這樣也能讓專案順利編譯成功!

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>8</source>
          <target>8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  ...
</project>

再重新執行一次 mvn compilemvn clean compile 也會發現專案依然可以成功建置!

注意: 執行 mvn clean compile 命令意味著先執行 clean 階段,再執行 compile 階段!

image

除了上述兩種方法外,還有一種直接透過 CLI 傳入 -D 指定 maven.compiler.sourcemaven.compiler.target 屬性的用法,也可以在執行時動態改變編譯器版本設定,詳見 compiler:compileOptional Parameters 說明:

mvn clean compile '-Dmaven.compiler.source=8' '-Dmaven.compiler.target=8'

這個方法也可以通過編譯!

將應用程式封裝成 JAR 檔

最後,我想在多介紹 Apache Maven JAR Plugin,如果我們想要把應用程式打包成 JAR 檔,就需要用到這個內建的 plugin,以本文的範例來說,還需要對這個 plugin 做出一些調整才行。

你至少需要加入以下設定到 pom.xml<project><build><plugins> 底下:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <addClasspath>true</addClasspath>
        <mainClass>com.duotify.App</mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

注意: 其實 <groupId>org.apache.maven.plugins</groupId> 是可以省略的,因為 org.apache.maven.plugins 這個 groupId 是 Maven 的預設值

然後執行以下 mvn clean package 命令即可產生 target\demo1-1.0-SNAPSHOT.jar 檔:

mvn clean package '-Dmaven.compiler.source=8' '-Dmaven.compiler.target=8'

接著就可以用以下命令直接測試執行:

java -jar target/demo1-1.0-SNAPSHOT.jar

總結

有了上述這個完整的例子,我相信你應該已經學會基本的 Maven Plugins 的運作架構與基本設定方法!👍

另外,你可以試試執行以下命令,他可以幫你找出你目前專案最終生效的 POM 檔完整內容,包含那些 Maven 內建的 POM 設定值,都會出現在執行結果中:

mvn help:effective-pom

上述命令事實上是執行 help plugin 的 effective-pom 目標(goal)!

你還可以利用以下命令,找出特定一個階段(phase)是哪些 plugins 有綁定目標(goal)

mvn help:describe -Dcmd=compile

他會顯示相當清楚的結果:

[INFO] 'compile' is a phase corresponding to this plugin:
org.apache.maven.plugins:maven-compiler-plugin:3.1:compile

It is a part of the lifecycle for the POM packaging 'jar'. This lifecycle includes the following phases:
* validate: Not defined
* initialize: Not defined
* generate-sources: Not defined
* process-sources: Not defined
* generate-resources: Not defined
* process-resources: org.apache.maven.plugins:maven-resources-plugin:2.6:resources
* compile: org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
* process-classes: Not defined
* generate-test-sources: Not defined
* process-test-sources: Not defined
* generate-test-resources: Not defined
* process-test-resources: org.apache.maven.plugins:maven-resources-plugin:2.6:testResources
* test-compile: org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile
* process-test-classes: Not defined
* test: org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test
* prepare-package: Not defined
* package: org.apache.maven.plugins:maven-jar-plugin:2.4:jar
* pre-integration-test: Not defined
* integration-test: Not defined
* post-integration-test: Not defined
* verify: Not defined
* install: org.apache.maven.plugins:maven-install-plugin:2.4:install
* deploy: org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy

相關連結

留言評論