开头说
这一讲来说Maven的生命周期。我们先来介绍三种标准的生命周期,接着介绍生命周期的绑定,最后是构建自定义的生命周期和生命周期扩展。
生命周期
生命周期概念
生命周期(lifecycles)是一系列阶段(phases)的集合。就像普通的程序员的生命周期是23-25是少年阶段,25-30是青年阶段,30-35是中年阶段,35后就步入老年阶段。[手动哀声叹气–sign!]
如果没有Maven,我们的日常工作经常是下载项目,编译,开发,测试,打包,部署等等。(我一个月薪4、5k的小小程序员,你竟然要求我做那么多!^_^)。这一套周期显然涉及各种阶段性的任务,Maven就是对以上工作抽取和统一。
三种标准生命周期
Clean生命周期
包含3个阶段,pre-clean、clean、post-clean。(这里的clean是阶段,不多恰巧和周期的名字重名。)
我们敲的命令,如 mvn clean 中的clean是指的阶段。阶段具有顺序性,因此在执行clean之前会先执行pre-clean。clean阶段的具工作是通过插件来完成的。我们可以通过 help 命令来查看细节:
$ mvn help:describe -Dplugin=clean
Name: Maven Clean Plugin
Description: The Maven Clean Plugin is a plugin that removes files generated
at build-time in a project's directory.
Group Id: org.apache.maven.plugins
Artifact Id: maven-clean-plugin
Version: 2.5
Goal Prefix: clean
This plugin has 2 goals:
clean:clean
Description: Goal which cleans the build.
This attempts to clean a project's working directory of the files that were
generated at build-time. By default, it discovers and deletes the
directories configured in project.build.directory,
project.build.outputDirectory, project.build.testOutputDirectory, and
project.reporting.outputDirectory.
Files outside the default may also be included in the deletion by
configuring the filesets tag.
clean:help
Description: Display help information on maven-clean-plugin.
Call
mvn clean:help -Ddetail=true -Dgoal=<goal-name>
to display parameter details.
For more information, run 'mvn help:describe [...] -Ddetail'
上面说的很清楚,这些工作是由Maven Clean Plugin完成的,下面给出该插件的groupId、artifactId和version。接着说该插件有两部分(goals),一个是提供clean功能,一个是提供帮助说明。
goal可以自己执行,也可以注册到生命周期中执行。单独执行的语法是这样的(第一个clean代表插件的名称,第二个代表插件中的目标goal):
$ mvn clean:clean
但是这里只会执行当前的目标,而若放在生命周期中执行,前面的阶段也会执行。
下面的代码揭示插件与Clean生命周期的clean阶段的关系(id标识生命周期,phase标识阶段):
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>default-clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
Clean生命周期中的pre-clean和post-clean没有做任何工作,他们的出现只是方便用户个性化配置。可以在clean前和后做自己想做的事情。
Default生命周期
Default生命周期包含23个阶段,如图所示:
下面对其一一说明:
- validate: 验证pom文件
- initialize:初始化文件目录,初始化配置文件中的属性
- generate-sources:生成需要的源码
- process-sources:处理源码
- generate-resources:生成资源文件
- process-resources:把资源文件拷贝到目标目录
- compile:编译
- process-classes:字节码增强处理
- generate-test-sources:生成测试需要的源码
- process-test-source:处理测试源码
- 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:写入远程资源库
当然这些阶段的某些不是必要的。由于不同打包类型的阶段任务不同,特定阶段使用的插件类型也不同。比如,jar的package阶段使用的插件是maven-jar-plugin,war的package阶段使用的插件是maven-war-plugin。从下一节可以知道,Default生命周期的声明中没有配置插件,仅是定义了23个阶段。
Site生命周期
site生命周期用于生成项目的静态HTML。包含4个阶段:pre-site、site、post-site和site-deploy。
生命周期的绑定
Maven标准的生命周期和绑定的配置位于 MAVEN_HOME/lib/maven-core-3.6.3.jar 中的 META-INF/plexus/components.xml 中(plexus是一种Ioc容器)。注意Clean生命周期和Site生命周期都有与插件的绑定配置,而Default生命周期没有。
Default生命周期的配置如下所示:
<component>
<role>org.apache.maven.lifecycle.Lifecycle</role>
<implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
<role-hint>default</role-hint>
<configuration>
<id>default</id>
<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>
</configuration>
</component>
其中role声明接口,implementation是具体实现类。component是由role和role-hint一起标识的(role-hint不是必要的,如果role不重复的话)。
Clean生命周期的绑定配置:
<component>
<role>org.apache.maven.lifecycle.Lifecycle</role>
<implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
<role-hint>clean</role-hint>
<configuration>
<id>clean</id>
<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>
</configuration>
</component>
Site生命周期的绑定配置:
<component>
<role>org.apache.maven.lifecycle.Lifecycle</role>
<implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
<role-hint>site</role-hint>
<configuration>
<id>site</id>
<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>
</configuration>
</component>
后两个生命周期中default-phase标签中包含对应阶段的默认插件配置(配置的语法是 插件包:插件名称:版本:插件的goal)。而Deffalut生命周期没有这个标签,所以还需要额外的配置。
接下来让我们看一下jar打包方式对应的Default生命周期的各阶段插件配置:
<component>
<role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
<role-hint>jar</role-hint>
<implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
<configuration>
<lifecycles>
<lifecycle>
<id>default</id>
<phases>
<process-resources>
org.apache.maven.plugins:maven-resources-plugin:2.6:resources
</process-resources>
<compile>
org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
</compile>
<process-test-resources>
org.apache.maven.plugins:maven-resources-plugin:2.6:testResources
</process-test-resources>
<test-compile>
org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile
</test-compile>
<test>
org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test
</test>
<package>
org.apache.maven.plugins:maven-jar-plugin:2.4:jar
</package>
<install>
org.apache.maven.plugins:maven-install-plugin:2.4:install
</install>
<deploy>
org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy
</deploy>
</phases>
</lifecycle>
</lifecycles>
</configuration>
</component>
lifecycles标签标识生命周期,id标识生命周期的名字。可以看出23个阶段仅选8个阶段进行配置。
个性化生命周期
上面讲到Default的生命周期依打包的方式变化,目前的打包种类有:jar、ear、 war、pom、rar、 par、
ejb、ejb3等等.如果我们想自己定义一种打包方式呢?这时就需要个性化的配置了。让我们先从简单的开始,这次我们仅更改Default生命周期的配置,保留原有的各阶段定义不变。以下是maven-bundle-plugin,资源路径在 https://github.com/sonatype/sonatype-bundle-plugin/
blob/master/src/main/resources/META-INF/plexus/components.xml,它改写了Default生命周期中的package、install、deploy阶段,注意某些阶段可以包含多个插件的配置,用逗号分隔。
<component-set>
<components>
<component>
<role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
<role-hint>bundle</role-hint>
<implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
<configuration>
<lifecycles>
<lifecycle>
<id>default</id>
<phases>
<process-resources>org.apache.maven.plugins:maven-resourcesplugin: resources</process-resources>
<compile>org.apache.maven.plugins:maven-compilerplugin: compile</compile>
<process-test-resources>org.apache.maven.plugins:maven-resourcesplugin: testResources</process-test-resources>
<test-compile>org.apache.maven.plugins:maven-compilerplugin: testCompile</test-compile>
<test>org.apache.maven.plugins:maven-surefireplugin: test</test>
<package>org.apache.felix:maven-bundle-plugin:bundle</package>
<install>
org.apache.maven.plugins:maven-installplugin: install,
org.apache.felix:maven-bundle-plugin:install
</install>
<deploy>
org.apache.maven.plugins:maven-deployplugin: deploy,
org.apache.felix:maven-bundle-plugin:deploy
</deploy>
</phases>
</lifecycle>
</lifecycles>
</configuration>
</component>
</components>
</component-set>
接着我们尝试定义自己的生命周期,决定里面包含哪些阶段。
1. 首先,我们在component.xml(这个文件在 自身项目/src/main/resources/META-INF/plexus/component.xml)加入如下的内容。
<component-set>
<components>
<component>
<role>org.apache.maven.lifecycle.Lifecycle</role>
<role-hint>packt</role-hint>
<implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
<configuration>
<id>packt_lifecycle</id>
<phases>
<phase>get-code</phase>
<phase>build-code</phase>
<phase>run-tests</phase>
<phase>notify</phase>
</phases>
<default-phases>
<get-code>com.packt:com.packt.lifecycle.sample:get-code-goal</get-code>
<build-code>com.packt:com.packt.lifecycle.sample:build-code-goal</build-code>
<run-tests>com.packt:com.packt.lifecycle.sample:run-tests-goal</run-tests>
<notify>com.packt:com.packt.lifecycle.sample:notify-goal</notify>
</default-phases>
</configuration>
</component>
</components>
</component-set>
2. 定义Maven plain Old Java Object (MOJO),它用来定义插件的goal,每个类只能处理一个goal。它继承org.apache.maven.plugin.AbstractMojo ,代码如下:
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
/**
* @goal get-code-goal
* @requiresProject false
*/
public class GetCodeGoalMojo extends AbstractMojo {
public void execute() throws MojoExecutionException,
MojoFailureException {
System.out.println("get-code-goal");
}
}
注意第一个注解 @goal定义goal的名称,和xml配置中插件get-code冒号后面一致。这里没有具体逻辑,仅是打印一句话,另外的三个类似的类省略了。
3. 定义pom文件
为了接近真实生产情况,我们分成了两个pom。第一个通过mvn clean install 生成插件jar。
<!-- 插件pom文件 -->
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.packt</groupId>
<artifactId>com.packt.lifecycle.sample</artifactId>
<version>1.0.0</version>
<!-- 这个maven-plugin是固定的,告知maven把该项目打包成插件 -->
<packaging>maven-plugin</packaging>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
</project>
这个执行后,本地仓库如下图:
<!-- 要使用packt_lifecycle生命周期打包的项目pom文件 -->
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.packt</groupId>
<artifactId>com.packt.lifecycle.sample.project</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>Custom Lifecycle Project</name>
<build>
<plugins>
<plugin>
<groupId>com.packt</groupId>
<artifactId>com.packt.lifecycle.sample</artifactId>
<version>1.0.0</version>
<extensions>true</extensions>
</plugin>
</plugins>
</build>
</project>
4. 执行上面的pom文件,注意需要先生成插件jar。
运行以下命令可以看到生命周期各阶段逐个执行。注意语法中的notify来源于自定义生命周期的最后一个阶段phase名称。
$ mvn notify
[INFO] Scanning for projects...
[INFO]
[INFO] ------------< com.packt:com.packt.lifecycle.sample.project >------------
[INFO] Building Custom Lifecycle Project 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- com.packt.lifecycle.sample:1.0.0:get-code-goal (default-get-code-goal) @ com.packt.lifecycle.sample.project ---
get-code-goal
[INFO]
[INFO] --- com.packt.lifecycle.sample:1.0.0:build-code-goal (default-build-code-goal) @ com.packt.lifecycle.sample.project ---
build-code-goal
[INFO]
[INFO] --- com.packt.lifecycle.sample:1.0.0:run-tests-goal (default-run-tests-goal) @ com.packt.lifecycle.sample.project ---
run-tests-goal
[INFO]
[INFO] --- com.packt.lifecycle.sample:1.0.0:notify-goal (default-notify-goal) @ com.packt.lifecycle.sample.project ---
notify-goal
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.160 s
[INFO] Finished at: 2020-04-12T09:30:11+08:00
[INFO] ------------------------------------------------------------------------
当然你也可以执行 mvn clean package。
本小讲的代码源于: 代码
为了方便,可以下载我传到CSDN的压缩包。
生命周期扩展
之前的个性化内容是构建内部的事情,那么我们还可以在构建之前和之后做一些事情,有点像切面处理。通过继承org.apache.maven.AbstractMavenLifecycleParticipant 类,重写3个中的任意方法。下面是对方法的说明:
- afterProjectsRead(MavenSession session): 当所有的MavenProject实例化(就是从pom文件转化的对象)之后被调用。
- afterSessionEnd(MavenSession session): 当所有工程构建后调用。比如用来清理构建过程中产生的资源文件。
- afterSessionStart(MavenSession session): 当MavenSession实例化之后,可用来设置执行参数,激活配置等。
以下举例说明:
package com.packt.lifecycle.ext;
import org.apache.maven.AbstractMavenLifecycleParticipant;
import org.apache.maven.MavenExecutionException;
import org.apache.maven.execution.MavenSession;
import org.codehaus.plexus.component.annotations.Component;
@Component(role = AbstractMavenLifecycleParticipant.class, hint
="packt")
public class PACKTLifeCycleExtension extends
AbstractMavenLifecycleParticipant {
@Override
public void afterProjectsRead(MavenSession session) {
System.out.println("All MavenProject instances are created.");
System.out.println("Offline building: " + session.isOffline());
}
@Override
public void afterSessionEnd(MavenSession session) throws
MavenExecutionException {
System.out.println("All Maven projects are built.");
}
}
该代码所在项目的pom文件,注意package是jar,与之前的例子生成插件不同。
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.packt</groupId>
<artifactId>com.packt.lifecycle.ext</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-compat</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 引入该插件只是为了生成源码的描述文件和类的注释 -->
<plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-component-metadata</artifactId>
<version>1.5.5</version>
<executions>
<execution>
<goals>
<goal>generate-metadata</goal>
<goal>generate-test-metadata</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
在上面的build成功之后,我们来构建项目:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.packt</groupId>
<artifactId>com.packt.lifecycle.ext.sample.project</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>Custom Lifecycle Extension Project</name>
<build>
<extensions>
<extension>
<groupId>com.packt</groupId>
<artifactId>com.packt.lifecycle.ext</artifactId>
<version>1.0.0</version>
</extension>
</extensions>
</build>
</project>
注意和之前的生命周期个性化引用不同,之前的那个是build/plugins,现在的是build/extensions。
执行mvn clean install:
[INFO] Scanning for projects...
All Maven project instances are created.
Offline building: false
[INFO]
[INFO] ----------< com.packt:com.packt.lifecycle.ext.sample.project >----------
[INFO] Building Custom Lifecycle Extension Project 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ com.packt.lifecycle.ext.sample.project ---
[INFO] Deleting C:\Users\renzh\Desktop\lifecycle-ext\com.packt.lifecycle.ext.project\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ com.packt.lifecycle.ext.sample.project ---
[WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory C:\Users\renzh\Desktop\lifecycle-ext\com.packt.lifecycle.ext.project\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ com.packt.lifecycle.ext.sample.project ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ com.packt.lifecycle.ext.sample.project ---
[WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory C:\Users\renzh\Desktop\lifecycle-ext\com.packt.lifecycle.ext.project\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ com.packt.lifecycle.ext.sample.project ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ com.packt.lifecycle.ext.sample.project ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ com.packt.lifecycle.ext.sample.project ---
[WARNING] JAR will be empty - no content was marked for inclusion!
[INFO] Building jar: C:\Users\renzh\Desktop\lifecycle-ext\com.packt.lifecycle.ext.project\target\com.packt.lifecycle.ext.sample.project-1.0.0.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ com.packt.lifecycle.ext.sample.project ---
[INFO] Installing C:\Users\renzh\Desktop\lifecycle-ext\com.packt.lifecycle.ext.project\target\com.packt.lifecycle.ext.sample.project-1.0.0.jar to R:\CodingRepository\MavenRepository\com\packt\com.packt.lifecycle.ext.sample.project\1.0.0\com.packt.lifecycle.ext.sample.project-1.0.0.jar
[INFO] Installing C:\Users\renzh\Desktop\lifecycle-ext\com.packt.lifecycle.ext.project\pom.xml to R:\CodingRepository\MavenRepository\com\packt\com.packt.lifecycle.ext.sample.project\1.0.0\com.packt.lifecycle.ext.sample.project-1.0.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.785 s
[INFO] Finished at: 2020-04-12T11:29:52+08:00
[INFO] ------------------------------------------------------------------------
All Maven projects are built.
可以看出使用的生命周期是默认的Default。但是开头和结尾执行了我们扩展类的逻辑。
本小讲的代码源于: 代码
为了方便,可以下载我传到CSDN的压缩包,该包对官方的进行了整理,官方的存有歧义。
小结
本讲介绍了3种生命周期以及它与插件之间的绑定方式,要注意Default生命周期与其他不同,它不与插件直接绑定,而是在特定的打包方式绑定。
接着介绍如何自定义生命周期以及在(构建)生命周期之前和之后切面处理。
建议先看前面的讲解:
小强说Maven(一)
转载:https://blog.csdn.net/qq_39722475/article/details/105449094