03.Maven学习笔记–Maven生命周期与插件开发
Maven 生命周期
知识点概要
- 生命周期的概念与意义
- Maven 三大生命周期与其对应的 phase (阶段)
- 生命周期与插件的关系
- 生命周期与默认插件的绑定
生命周期的概念与意义
在项目构建时通常会包含清理、编译、测试、打包、验证、部署,文档生成等步骤,Maven 统一对其进行了整理,抽像成三个生命周期 (lifecycle) 及各自对应的多个阶段 (phase)。
这么做的意义是:
- 每个阶段都成为了一个扩展点,可以采用不同的方式来实现,提高了扩展性与灵活性;
- 规范统一了 Maven 的执行路径。
在执行项目构建阶段时可以采用 jar 包方式构建,也可以采用 war 包方式构建,提高了灵活性。
可以通过命令
mvn ${phase name}
直接触发指定阶段的执行。
演示 phase 的执行:
#执行清理phase
mvn clean
#执行compile phase
mvn compile
# 也可以同时执行 清理加编译
mvn clean compile
Maven 三大生命周期与其对应的 phase (阶段)
Maven 总共包含三大生命周期:
- clean Lifecycle:清理生命周期,用于清理项目
- default Lifecycle:默认生命周期,用于编译、打包、测试、部署等
- site Lifecycle:站点文档生成,用于构建站点文档
参考:
http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
Clean Lifecycle
Phase | Description |
---|---|
pre-clean |
execute processes needed prior to the actual project cleaning |
clean |
remove all files generated by the previous build |
post-clean |
execute processes needed to finalize the project cleaning |
Default Lifecycle
Phase | Description |
---|---|
validate |
validate the project is correct and all necessary information is available. |
initialize |
initialize build state, e.g. set properties or create directories. |
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 |
process-test-classes |
post-process the generated files from test compilation, for example to do bytecode enhancement on Java classes. |
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. |
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. |
Site Lifecycle
Phase | Description |
---|---|
pre-site |
execute processes needed prior to the actual project site generation |
site |
generate the project’s site documentation |
post-site |
execute processes needed to finalize the site generation, and to prepare for site deployment |
site-deploy |
deploy the generated site documentation to the specified web server |
三大生命周期相互独立执行,也可以合在一起执行。但 lifecycle 中的 phase 是有严格执行的顺序的,比如必须是先执行完 compile 才能执行 pakcage 动作。此外 phase 还有“包含”逻辑,即当你执行一个 phase 时其前面的 phase 会自动执行。
演示 phase 执行:
# 执行编译
mvn compile
# 执行打包就包含了编译指令的执行
mvn package
实例
mvn compile
ll
mvn pre-clean
ll
mvn post-clean
ll
mvn package
ll
生命周期与插件的关系
参考:http://maven.apache.org/ref/3.5.4/maven-core/lifecycles.html
生命周期的 phase 组成了项目过建的完整过程,但这些过程具体由谁来实现呢?
Maven 的核心部分代码量其实很少,其大部分实现都是由插件来完成的。比如:test 阶段就是由 maven-surefire-plugin 实现的。在 pom.xml 中我们可以设置指定插件目标 (goal) 与 phase 绑定,当项目构建到达指定phase 时就会触发些插件 goal 的执行。 一个插件有时会实现多个 phas,比如:maven-compiler-plugin 插件分别实现了 compile 和 testCompile。
总结:
- 生命周期的阶段可以绑定具体的插件及目标
- 不同配置下同一个阶段可以对应多个插件和目标
- phase –> plugin –> goal (功能)
生命周期与插件的默认绑定
在我们的项目当中并没有配置 maven-compiler-plugin 插件,但当我们执行 compile 阶段时一样能够执行编译操作,原因是 Maven 默认为指定阶段绑定了插件实现。例如以下两个操作在一定程度上是等价的:
mvn compile
#直接执行compile插件目标
mvn org.apache.maven.plugins:maven-resources-plugin:2.6:resources
mvn org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
默认绑定可以从
%MAVEN_HOME%/lib/maven-core-3.5.4.jar/META-INF/plexus/default-bindings.xml
文件中查看。
clean Lifecycle 默认绑定:
<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>
site Lifecycle 默认绑定:
<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>
Default Lifecycle JAR 默认绑定:
<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>
注:不同的项目类型其默认绑定是不同的,这里只指列举了 packaging 为 jar 的默认绑定,全部的默认绑定参见:
https://maven.apache.org/ref/3.5.4/maven-core/default-bindings.html
Maven 自定义插件开发
知识点概要:
- 插件的相关概念
- 常用插件的使用
- 开发一个自定义插件
Maven 插件相关概念
插件坐标定位
插件与普通 jar 包一样包含一组件坐标定位属性,即:
- groupId
- artifactId
- version
当使用该插件时会从本地仓库中搜索,如果没有就从远程仓库下载。
<!-- 唯一定位到dependency 插件 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
插件执行 execution
参考:http://maven.apache.org/plugins/index.html
http://maven.apache.org/plugins/maven-dependency-plugin/examples/copying-project-dependencies.html
execution 配置包含一组指示插件如何执行的属性:
- id : 执行器命名
- phase:执行的阶段
- goals:执行一组什么目标或功能
- configuration:执行目标所需的配置文件
演示一个插件的配置与使用:
<!--将插件依赖拷贝到指定目录-->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>compile</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/alternateLocation</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
<excludeTransitive>true</excludeTransitive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
常用插件的使用
除了通过配置的方式使用插件以外,Maven 也提供了通过命令直接调用插件目标的方式。
其命令格式如下:
mvn groupId:artifactId:version:goal -D{参数名}
演示通过命令执行插件:
展示 pom 的依赖关系树
# 展示pom的依赖关系树
mvn org.apache.maven.plugins:maven-dependency-plugin:2.8:tree
# 也可以直接简化版的命令,但前提必须是maven 官方插件
mvn dependency:tree
其它常用插件:
# 查看pom文件的最终配置
mvn help:effective-pom
# 原型项目生成
mvn archetype:generate
#快速创建一个WEB程序
mvn archetype:generate -DgroupId=demo.yangxu -DartifactId=yangxu-simple-webbapp -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
#快速创建一个Java项目
mvn archetype:generate -DgroupId=demo.yangxu -DartifactId=simple-java -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
# -DinteractiveMode=false是否以交互模式进行
#如果是false的话就会采用默认设置建立项目
#-DarchetypeArtifactId指是的原型ID
查看 pom 文件的最终配置
<?xml version="1.0" encoding="UTF-8"?>
<!-- ====================================================================== -->
<!-- -->
<!-- Generated by Maven Help Plugin on 2020-08-31T14:14:48+08:00 -->
<!-- See: http://maven.apache.org/plugins/maven-help-plugin/ -->
<!-- -->
<!-- ====================================================================== -->
<!-- ====================================================================== -->
<!-- -->
<!-- Effective POM for project 'demo.yangxu:yangxu-client:jar:1.0-SNAPSHOT' -->
<!-- -->
<!-- ====================================================================== -->
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>demo.yangxu</groupId>
<artifactId>yangxu-maven</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>demo.yangxu</groupId>
<artifactId>yangxu-client</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.4.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</pluginRepository>
</pluginRepositories>
<build>
<sourceDirectory>D:\mavenLearn\yangxu-maven\yangxu-client\src\main\java</sourceDirectory>
<scriptSourceDirectory>D:\mavenLearn\yangxu-maven\yangxu-client\src\main\scripts</scriptSourceDirectory>
<testSourceDirectory>D:\mavenLearn\yangxu-maven\yangxu-client\src\test\java</testSourceDirectory>
<outputDirectory>D:\mavenLearn\yangxu-maven\yangxu-client\target\classes</outputDirectory>
<testOutputDirectory>D:\mavenLearn\yangxu-maven\yangxu-client\target\test-classes</testOutputDirectory>
<resources>
<resource>
<directory>D:\mavenLearn\yangxu-maven\yangxu-client\src\main\resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>D:\mavenLearn\yangxu-maven\yangxu-client\src\test\resources</directory>
</testResource>
</testResources>
<directory>D:\mavenLearn\yangxu-maven\yangxu-client\target</directory>
<finalName>yangxu-client-1.0-SNAPSHOT</finalName>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>compile</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>D:\mavenLearn\yangxu-maven\yangxu-client\target/alternateLocation</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
<excludeTransitive>true</excludeTransitive>
</configuration>
</execution>
</executions>
</plugin>
<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>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>default-testResources</id>
<phase>process-test-resources</phase>
<goals>
<goal>testResources</goal>
</goals>
</execution>
<execution>
<id>default-resources</id>
<phase>process-resources</phase>
<goals>
<goal>resources</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>default-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<executions>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>default-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>default-install</id>
<phase>install</phase>
<goals>
<goal>install</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>default-deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.3</version>
<executions>
<execution>
<id>default-site</id>
<phase>site</phase>
<goals>
<goal>site</goal>
</goals>
<configuration>
<outputDirectory>D:\mavenLearn\yangxu-maven\yangxu-client\target\site</outputDirectory>
<reportPlugins>
<reportPlugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
</reportPlugin>
</reportPlugins>
</configuration>
</execution>
<execution>
<id>default-deploy</id>
<phase>site-deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
<configuration>
<outputDirectory>D:\mavenLearn\yangxu-maven\yangxu-client\target\site</outputDirectory>
<reportPlugins>
<reportPlugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
</reportPlugin>
</reportPlugins>
</configuration>
</execution>
</executions>
<configuration>
<outputDirectory>D:\mavenLearn\yangxu-maven\yangxu-client\target\site</outputDirectory>
<reportPlugins>
<reportPlugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
</reportPlugin>
</reportPlugins>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<outputDirectory>D:\mavenLearn\yangxu-maven\yangxu-client\target\site</outputDirectory>
</reporting>
</project>
原型项目生成
快速创建一个 WEB 程序
快速创建一个 Java 项目
开发一个自定义插件
Maven 插件的命名规范
一般来说,我们会将自己的插件命名为 xx-maven-plugin,而不推荐使用 maven-xx-plugin,因为后者是 Maven 团队维护官方插件的保留命名方式,使用这个命名方式会侵犯 Apache Maven 商标。
什么是 Mojo
Mojo 就是Maven plain Old Java Object。每一个 Mojo 就是 Maven 中的一个执行目标(executable goal),而插件则是对单个或多个相关的 Mojo 做统一分发。一个 Mojo 包含一个简单的 Java 类。插件中多个类似 Mojo 的通用之处可以使用抽象父类来封装。
实现步骤:
- 创建 Maven 插件项目(命名示例:yangxu-maven-plugin)
- 设定 packaging 为 maven-plugin
- 添加插件依赖
- 编写插件实现逻辑
- 打包构建插件
插件 pom 配置:
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>demo.yangxu</groupId>
<artifactId>yangxu-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>maven-plugin</packaging>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.4</version>
</dependency>
</dependencies>
</project>
插件实现类:
package demo.yangxu.maven.plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
@Mojo(name = "yangxu")
public class YangxuPlugin extends AbstractMojo {
@Parameter
String sex;
@Parameter
String description;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
getLog().info(String.format("yangxu sex=%s, description=%s",sex,description));
}
}
将插件安装到本地仓库:
调用插件 pom 配置:
<build>
<plugins>
<plugin>
<groupId>demo.yangxu</groupId>
<artifactId>yangxu-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<executions>
<execution>
<id>print-yangxu-info</id>
<phase>compile</phase>
<goals>
<!--对应@Mojo(name = "yangxu")-->
<goal>yangxu</goal>
</goals>
<configuration>
<sex>man</sex>
<description>Java programmer</description>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
对调用插件的项目执行编译: