首页 > 代码库 > Maven 的插件和生命周期的绑定

Maven 的插件和生命周期的绑定

一、Maven 的生命周期

Maven 的生命周期是对所有的构建过程进行抽象和统一。Maven 的生命周期是抽象的,这意味着生命周期本身不做任何实际的工作,生命周期只是定义了一系列的阶段,并确定这些阶段的执行顺序。

Maven 有三套相互独立的生命周期,分别是 clean、default和 site。生命周期( lifecycle )由多个阶段( phase )组成,每个阶段( phase )会挂接一到多个goal。Goal 是 maven 里定义任务的最小单元,如下表:

生命周期( Lifecycle )

阶段( Phase )

目标( Goa l)

clean

clean

maven-clean-plugin:clean

default

process-resources

maven-resources-plugin:resources

compile

maven-compiler-plugin:compile

generate-test-resources

maven-resources-plugin:testResouces

test-compile

maven-compiler-plugin:testCompile

test

maven-surefire-plugin:test

package

打包类型是jar时:maven-jar-plugin:jar;

打包类型是war时:maven-war-plugin:war

install

maven-install-plugin:install

deploy

maven-deploy-plugin:deploy

site

site

maven-site-plugin:site

site-deploy

maven-site-plugin:deploy

 

二、 Maven 插件和生命周期的绑定

Maven 的插件位于 ${REPOSITORY_HOME}\org\apache\maven\plugins 。用户和 Maven 最直接的交互方式就是调用这些生命周期阶段,而在执行这些阶段时,实际的任务主要由插件来完成。
  1. 以 Phase 为目标的构建
    以 phase 为目标进行构建是最常见的,如我们平时经常执行的 mvn compile,mvn test,mvn package...等等, compile, test, package 都是 maven 生命周期( lifecycle )里的 phase,通过 mvn 命令,你可以指定一次构建执行到哪一个阶段,在执行过程中,所有经历到的执行阶段( phase )上绑定的 goal 都将得到执行。例如,对于一个jar包应用,当执行mvn package命令时,maven 从 validate 阶段一个阶段到一个阶段的执行,在执行到 compile 阶段时,compiler 插件的 compile goal 会被执行,因为这个 goal 是绑定在compile阶段( phase )上的。这一点可从其对应的 mojo 类上得知:
    技术分享
    再比如经常使用的打包插件 shade,它的 goal 是绑定到package阶段的,这样,使用 mvn package 进行打包时都会执行 shade 的。
    技术分享
  2. 以 Goal 为目标的构建
    虽然以 phase 为目标的构建最常见,但是有时候我们会发现,一些插件的 goal 并不适合绑定到任何阶段( phase )上,或者是这些 goal 往往是单独执行,不需要同某个阶段( phase )绑定在一起,比如 jetty(6.1.26)插件,它的 goal 都是将打包或未打包的工程部署到 jetty 里然后启动 jetty 容器的,多数情况下,人们都是独立运行这些goal的,比如:人们希望当键入 mvn jetty:run 后,工程就能完成编译后启动 jetty。而 jetty 插件也确实是这样做的,它的 run goal 的 mojo 是这样声明的:
    技术分享
    其中 @execute phase="test-compile" 指明 jetty:run 这一 goal 会促使 maven 先 build 到 test-compile 阶段,再执行这个 goal。同样,对于 jetty:run-war 这个goal 则要求先 build 到 package 阶段再执行该 goal。
    技术分享
    而另外一个例子是exec插件的exec:java.
    技术分享
    这个 goal 也声明了 execute 的 phase,但却是 validate,这样,如果代码没有编译,执行这个 goal 就会出错,所以多数情况下,人们总是使用下面的方式执行的:mvn clean compile exec:java
    Maven 支持这种方式是因为有些任务不适合绑定到生命周期上。
    在命令行调用插件的格式如下:
      mvn groupId:artifactId:version:goal
    其中 groupId、artifactId、version 共同表示了插件的坐标,goal 则表示插件目标的方法。
    但我们看到很多执行插件目标的格式与之并不相符,例如文章开头的 mvn jetty:run,jetty并不是 groupId、artifactId或version 而是插件的前缀,这就有了第二种调用插件的格式:
      mvn 前缀:goal

    Maven 通过查询插件仓库的元数据才得知插件前缀对应插件的 groupId、artifactId,而如果插件是Maven的核心插件则在超级POM中已经定义了插件的版本,如果不是核心插件,则默认取最新的release版本 。
    Maven的插件仓库默认是 http://repo1.maven.org/maven2/org/apache/maven/plugins/ 和 http://repository.codehaus.org/org/codehaus/mojo/,相应的查询插件仓库元数据时会默认使用 org.apache.maven.plugins 和 org.codehaus.mojo 两个 groupId。但也可以通过配置 settings.xml 让Maven检查其他 groupId 上的插件仓库元数据,如:

    <settings>        <pluginGroups>        <pluginGroup>com.your.plugins</pluginGroup>    </pluginGroups></settings>

    这样配置后,Maven就不只检查 org/apache/maven/plugins/maven-metadata.xml 和 org/codehaus/mojo/maven-metadata.xml,还会检查com/your/plugins/maven-metadata.xml

  3. 相关配置实例
    如果我们想在 test 阶段只执行单元测试,而在 integration-test 阶段进行集成测试的话,可以如下配置:
    <plugin>    <groupId>org.apache.maven.plugins</groupId>    <artifactId>maven-surefire-plugin</artifactId>    <version>2.10</version>    <configuration>        <skip>true</skip>    </configuration>    <executions>        <execution>            <id>run-test</id>            <phase>test</phase>            <goals>                <goal>test</goal>            </goals>            <configuration>                <skip>false</skip>                <includes>                    <include>**/unit/**/*.java</include>                </includes>            </configuration>        </execution>        <execution>            <id>run-integration-test</id>            <phase>integration-test</phase>            <goals>                <goal>test</goal>            </goals>            <configuration>                <skip>false</skip>                <includes>                    <include>**/integration/**/*.java</include>                </includes>            </configuration>        </execution>    </executions></plugin>

    其中红色背景的 <skip>true</skip> 是为了让 Maven 的默认绑定(test阶段<-> maven-surefire-plugin:test 插件目标) 无效 (其实绑定仍然有效,只是执行时忽略执行罢了),而后面的 executions 块内容则增加了两个绑定,分别将 maven-surefire-plugin:test 插件目标绑定到 test 阶段和 integration-test 阶段,只是配置不一样了,分别执行unit包和integration包下的测试类。

三、参考文档

  • Maven lifecycle
  • Maven plugins
  • maven的生命周期和插件 - 御云
  • 是goal还是phase?Maven插件(plugin)goal的执行与生命周期(lifecycle)phase的关系

Maven 的插件和生命周期的绑定