maven build lifecycle

 
Build Lifecycle
Maven 2 是围绕着 Build Lifecycle 概念设计的。这意味着,构建或者发布的过程已经被清晰的定义了。
 
Build lifecycle 是由 a set 有依次顺序的 phases 组成的。当我们使用Maven构建工程时,我们只需要了解自己希望做什么,然后执行对应的lifecycle phase即可。
 
例如,我们希望编译我们的工程,在命令行状态下 进入到工程的pom.xml文件所在的目录中,使用命令:mvn compile;希望构建打包我们的工程,使用mvn package即可。
 
每个LifeCycle phase 实质上都会绑定到某个plugin:goal 上!!例如命令
mvn compile
实际上等价于
            mvn compiler:compile
即执行compile phase命令=执行compiler plugin的compile goal
 
但有一个很关键的知识点: pom.xml <packaging> 的值不同,会影响lifecycle phase 与哪个plugin:goal 的绑定。例如:
如果是
<packaging>jar</packaging>
那么
package phase绑定到jar:jar
            mvn package = mvn jar:jar
           
如果是
<packaging>war</packaging>
那么
package phase绑定到war:war
            mvn package = mvn war:war
 
 
default lifecycle 里,包含下列最常用被执行的 phases(文章最后会给出lifecycle phases的完整列表)
  • validate : validate the project is correct and all necessary information is available
  • compile : compile all java files in project
  • test : 使用unit test frameworktest the compiled source code。这些test class不会被packaged and deployed
  • package : compiled code打包成你需要的格式,如JAR.
  • integration-test : 把已经打包的东东(如jardeploy到运行环境内,用于集成测试
  • verify : run any checks to verify the package is valid and meets quality criteria
  • install : install the package into the local repository, 这样做的目的是作为其他projects的一个local dependency
  • deploy : phasecopy final packageremote repository for sharingThis phase is done in an integration or release environment
另外还有 3 个很常用的、但不属于 default lifecycle phase
  • clean : cleans up artifacts created by prior builds
  • site : generates site documentation for this project
  • eclipse:eclipse : 创建相关的eclipse ide文件  
 
当你执行一个 phase 命令时, maven 就会执行顺序排在该 phase 之前的所有 phases ,然后再执行该 phase 例如,如果我们执行 compile” phase ,那么 maven 实际要执行的 phases 依次为:
1.       validate
2.       generate-sources
3.       process-sources
4.       generate-resources
5.       process-resources
6.       compile
 
一个mvn 命令可以同时执行多个phases,如:
mvn clean install
该命令是先执行clean phase,然后执行install phase
 
 
<packaging> lifecycle phase
pom.xml <packaging> 的值 ( 缺省为 ) 会直接影响 mvn lifecycle phase 的执行操作,即不同的值将直接影响 lifecycle phase 与哪个 plugin:goal 的绑定。
 
 
例:
1)如果是<packaging>jar</packaging>,那么lifecycle phases与plugin:goal的绑定为( 左边为 lifecycle 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
 
看上面列表,其中 最值得注意的是 package phase 绑定到了 jar:jar
执行mvn package = mvn jar:jar
 
2)如果是 <packaging>war</packaging>,那么package phase会绑定到war:war上,执行 mvn package = mvn war:war
 
3)如果是 <packaging>pom</packaging>,那么上面列表中 只有“install” and “deploy”被绑定到,而其他phases则没有被绑定到。也就是说如果执行mvn package,则什么操作也没执行。
 
 
另外一个很重要的知识点是: 有一些<packaging>值的使用,必须在pom.xml里添加相应的<plugin>配置信息。
 
例如:如果你要使用
<packaging> plexus-application <packaging>
or
<packaging> plexus-service <packaging>
就必须在 pom.xml 里添加 Plexus ” plugin 配置。
 
 
<plugin> lifecycle phase
 
<plugin> element 可以给 lifecycle phase 添加要执行的 goal,<plugin>设置的goal将会被添加到goal list goals which already bound to the lifecycle from the packaging selected。这时 某个phase被绑定了1个以上的goal,那么在执行该phasemvn命令时,会先执行<packaging>本身所绑定的goal,然后再执行<plugin>绑定的goals。你更可以使用<plugin>child element <executions>来控制goal的执行顺序
 
例:有一个Modello plugin,它总是绑定modello:java到generate-sources phase(注意: 设置绑定不是在你的pom.xml里,而是plugin本身已经设置好了的!!
 
如果你的project想使用Modello plugin来generate sources from a model,那么就需要在pom.xml里的<build>里的<plugins>里添加下列代码:
 
...
 <plugin>
   <groupId>org.codehaus.modello</groupId>
   <artifactId>modello-maven-plugin</artifactId>
   <executions>
     <execution>
       <configuration>
         <model>maven.mdo</model>
         <modelVersion>4.0.0</modelVersion>
       </configuration>
       <goals>
         <goal>java</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
...
 
为什么要使用<executions> 这是因为 使用它可以对同一个goal根据不同的<configuration>来执行多次。
 
如果有多个匹配某个phase <execution> ,那么他们将会被依次按顺序执行(当然,被继承的execution 会先被执行)
 
我们再来考虑这样一种情况:上面提到Modello plugin的goal(modello:java)被绑定到generate-sources phase( 注意:设置绑定不是在你的 pom.xml 里,而是 plugin 本身已经设置好了的!!), 如果我还希望该goal能够同时也绑定到另外的、非内在绑定的phase上,怎么办呢?很简单,只需要在<execution>里使用<phase>来设置。例如,你有一个goal touch:timestamp,它是用来输出某个file的timestamp,该goal内在绑定到test phase,你希望能把它也绑定到process-test-resources上,则使用下列代码:
...
 <plugin>
   <groupId>com.mycompany.example</groupId>
   <artifactId>touch-maven-plugin</artifactId>
   <executions>
     <execution>
       <phase>process-test-resources</phase>
       <configuration>
         <file>${project.output.directory}/timestamp.txt</file>
       </configuration>
       <goals>
         <goal>timestamp</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
...
 
 
lifecycle phases的完整列表(按执行的先后顺序)
validate
validate the project is correct and all necessary information is available.
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
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.
 
 
Build lifecycle plugin 开发
开发Plugin 简单来说就是开发一组“根据输入和输出参数来执行某些操作”的goals (也就是mojo ),然后把goal 绑定到相应的lifecycle phase 上去。
 
Plugin 通过 3 种方式来与 lifecycle phase 进行绑定
  • 绑定一个mojo到一个特定的phase上
  • 定义一个packaging type(即定义一个pom.xml中<packaging>的值),并设置相应的lifecycle bindings
  • forking a parallel lifecycle
 
Binding a Mojo to a Phase
mojo 上添加 annotation @phase 来把 mojo 绑定到某个 lifecycle phase 上。如下面的 annotation 就是把 mojo 绑定到 generate-sources phase 上:
@phase generate-sources
这样,当 MOJO 对应的 GOAL POM.XML 里有进行设置,那么该 goal 就会在绑定的 phase 里被执行。
 
定义一个 packaging type (即定义一个 pom.xml <packaging> 的值)
如果你的 plugin 希望提供一个特别的 artifact type ,也就是提供一个特别的 <packaging> 值,那么你不仅需要提供 package phase 要绑定的 goal ,还需要提供其他 default lifecycle phases goals 的绑定。
定义 packaging type 是在 plugin jar META-INF/plexus/components.xml 。下面的例子是 Plexus plugin register 一个 packaging type:   plexus-application
<component-set>
 <components>
    <component>
      <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
      <role-hint>plexus-application</role-hint>
      <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
      <configuration>
        <phases>
          <process-resources>org.apache.maven.plugins:maven-resources-plugin:resources</process-resources>
          <compile>org.apache.maven.plugins:maven-compiler-plugin:compile</compile>
          <process-test-resources>org.apache.maven.plugins:maven-resources-plugin:testResources</process-test-resources>
          <test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
          <test>org.apache.maven.plugins:maven-surefire-plugin:test</test>
          <package>org.codehaus.plexus:plexus-maven-plugin:app</package>
          <install>org.apache.maven.plugins:maven-install-plugin:install</install>
          <deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
        </phases>
      </configuration>
    </component>
 </components>
</component-set>
在上面的代码中,
< role-hint> 的值是新定义的 packaging type
<role> 的值为 org.apache.maven.lifecycle.mapping.LifecycleMapping ,表示这是为 packaging 进行的 lifecycle 绑定。
< implementation> element 是必须的,该例子是使用缺省的 implementation.
<configuration> element 里是为这个新定义的 packaging type 设置被绑定的 phases list 。列表中的每一个 phase 都会被绑定到一个 goal 上。请注意 goal 设置必须是 "fully qualified" (格式为: groupId:artifactId:goal or groupId:artifactId:version:goal )。
值得留意的是:上述代码只是把 package phase 绑定到自定义 plugin app goal 上,其他 phase 还是绑定到缺省的 goal 上。
针对上面代码定义的 packaging type “ plexus-application ,如果你要在你的 project 里使用它,你的 pom.xml 应该类似于:
...
 <packaging>plexus-application</packaging>
...
 <plugin>
   <groupId>org.codehaus.plexus</groupId>
   <artifactId>plexus-maven-plugin</artifactId>
   <extensions>true</extensions>
 </plugin>
...
注意:如果你使用自定义的 artifact type handlers ,那么就必须设置 <extensions>
One final task that is required is for the packaging goal you have created to tell Maven where to find what you built. This is done with code such as the following:
project.getArtifact().setFile( new File( "target/myFile-2.0.jar" ) );
 
如何定义一个 Custom Artifact Handler
缺省的 artifact handler packaging, type, and file extension 映射成相同的值 。例如,如果你定义了一个 packaging 为“ plexus-application ”,那么在 repository 里对应的 file 为“ myartifactId-1.0.plexus-application ”。这个规则也适用于 a particular type from a dependency.
如果你想修改 extension, 或者想修改 a dependency's type field 映射到其他 fields 的方式,你必须在你的 plugin jar 里的 META-INF/plexus/components.xml 里配置一个 custom artifact handler
下面代码是 A complete artifact handler for the test-jar type:
<component-set>
 <components>
    <component>
      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
      <role-hint>test-jar</role-hint>
      <implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
      <configuration>
        <classifier>tests</classifier>
        <extension>jar</extension>
        <type>test-jar</type>
        <packaging>jar</packaging>
        <language>java</language>
        <addedToClasspath>true</addedToClasspath>
      </configuration>
    </component>
 </components>
</component-set>
The fields are configured as follows:
Field
Required?
Default
Description
role-hint
Y
 
The type being defined.
type
Y
 
Must match the role-hint .
extension
N
The type
The extension to give the artifact in the repository.
packaging
N
The type
The packaging of the artifact to look for.
classifier
N
 
The classifier to append to the artifact name (after version and before extension) when using this type.
language
N
java
The language the artifact is written in. No set values – free text.
addedToClasspath
N
true
Whether the artifact should be included in a classpath or library path when used.
includesDependencies
N
false
If the artifact already includes all of its dependencies, this setting ensures they are not propogated transitively.
因此,只要该 plugin declare 同时 type 被用到,如果使用 custom artifact handler ,就必须设置 <extensions> element
 
Forking a Parallel Lifecycle
While lots of mojos will participate in the standard lifecycle, there are just as many that are used in other scenarios. These are mojos that are executed standalone from the command line (such as idea:idea ), or individual reports in the site building process.
However, sometimes these goals require that a particular task has already been performed - for instance, the IDEA plugin must ensure sources have been generated to properly construct its module files. If the goal were participating in the lifecycle, it would easily do this by ensuring it occurred after the phase it depended on having run. Since this isn't the case, it must have a way to first execute that task.
Additionally, even goals participating in the build lifecycle might need to perform a task with different parameters to what was already used, and does not want the output to affect the current build (for example, running clover:check to run tests with modified sources and fail if a certain coverage ratio is not achieved).
For these reasons, mojos are capable of forking a new lifecycle. The lifecycle will be a normal build lifecycle, a clone of the one currently being used (including any additional bindings from the POM), executed up until the point specified by the mojo.
For example, the idea:idea mojo specifies the following in the mojo level declarations to call the source generation:
@execute phase="generate-sources"
But what happens if generate-sources has already been run in this build? In the current version of Maven, there is no way to tell if the previous execution used the same input and outputs as the current mojo requires, so the task (and any preceding ones if from the lifecycle) must be run again.
For this reason, it is important that if your plugin does any intensive work, you should first check whether it is necessary to perform the tasks again, perhaps by using timestamp checking or a similar technique. As an example, the compiler plugin will only recompile changed source files so can very efficiently be run multiple times in a build if necessary.
When the lifecycle is forked, the project object being used is also cloned. In this way, modifications made to the project as part of the execution, such as the addition of a new source root, will not affect the original build. When the lifecycle finishes executing and control is passed to the original mojo, it can access that project using the expression $executedProject . For example:
/**
 * @parameter expression="${executedProject}"
 */
private MavenProject executedProject;
This project instance can be used by the mojo to obtain results, and propogate any changes it sees fit into the original build.
Finally, when forking the new lifecycle, it is possible to augment it on top of the changes already made by the packaging and the plugins in the POM.
For example, consider the Clover plugin. If clover:check were to be run from the command line, the plugin would need to fork the lifecycle, executing the test phase. But, it would also need to add some configuration and bind the clover:compiler goal to the generate-sources phase.
This can be achieved by including the following file as META-INF/maven/lifecycle.xml in the plugin JAR:
<lifecycles>
 <lifecycle>
    <id>clover</id>
    <phases>
      <phase>
        <id>generate-sources</id>
        <executions>
          <execution>
            <configuration>
              <debug>true</debug>
            </configuration>
              <goals>
                <goal>compiler</goal>
              </goals>
          </execution>
        </executions>
      </phase>
    </phases>
 </lifecycle>
</lifecycles>
Here, the executions element is present in a similar way to a plugin declaration in the POM. This can be used to bind a goal one or more times to a particular phase, as well as specifying configuration. Note that configuration already provided in the POM to that plugin that is not part of a specific execution will also be applied.
The lifecycle ID given here ( clover ) can then be used in the mojo to specify what to overlay on the forked lifecycle when executing it, using the following mojo level declaration:
@execute phase="test" lifecycle="clover" 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值