Maven的一条命令背后究竟发生了啥:mvn clean install
这其实要涉及到Maven的生命周期、阶段以及插件目标三个部分。本章的学习思路如下所示:
什么是生命周期
生命就是从出生到死亡的一个过程,周期就是反复、定期可执行。当我们在【Maven】里执行一条命令时,这条命令就是基于生命周期展开的。具体来说,【Maven】有三种互不相干的、独立的生命周期:
clean
,清理default
,默认site
,站点
那我们的install
是哪个生命周期呢?上述三个生命周期内部还细致划分了许多个阶段 ( Phase ):
clean
,用于清理项目。它包含了三个阶段:pre-clean
,执行清理前的工作clean
,清理上一次构建生成的文件post-clean
,执行清理后的工作
default
,包含了所有真正构建时所需要的步骤,是所有生命周期中最核心的部分,其内部划分了以下几个阶段:validate
,验证项目的正确性以及必要信息的有效性。initialize
,初始化构建状态,比如设置属性、创建目录等等generate-sources
,生成包含在编译中的源码process-sources
,处理源码,做一些占位符替换generate-resources
,生成资源文件,并去处理各类XML
、properties
那种配置文件,并去做一些配置文件里面占位符替换process-resources
,将资源文件拷贝到目标目录中,方便后面打包compile
,编译项目的源代码process-classes
,处理编译后的代码文件,比如对Java Class
进行字节码增强generate-test-sources
,自动化生成测试代码process-test-sources
,处理测试代码,比如一些占位符generate-test-resources
,生成测试用的资源文件process-test-resources
,拷贝测试用的资源文件到目标目录中test-compile
,编译测试代码process-test-classes
,对编译后的测试代码进行处理,比如进行字节码增强test
,使用单元测试框架运行测试prepare-package
,在打包之前进行准备工作,比如处理package
的版本号package
,将代码进行打包,比如jar包
pre-integration-test
,在集成测试之前进行准备工作,比如建立好需要的环境integration-test
,将package部署到一个环境中以运行集成测试post-integration-test
,在集成测试之后执行一些操作,比如清理测试环境verify
,对package
进行一些检查来确保质量过关install
,将package
安装到本地仓库中,这样开发人员自己在本地就可以使用了deploy
,将package
上传到远程仓库中,这样公司内其他开发人员也可以使用了
site
,建立和发布项目的站点,Maven
能够基于pom.xml
所包含的信息,自动生成一个站点帮助团队开发与交流:pre-site
,执行一些在生成站点之前做的工作site
,生成项目站点文档post-site
,执行一些在生成站点之后做的工作site-deploy
,将生成的站点发布到服务器上
命令行确切来说是和生命周期的某个阶段相关,比如:
mvn clean
就是和生命周期:clean
中的阶段:clean
相连,会执行clean
生命周期中阶段:clean
之前所有的阶段(包括阶段:clean
)mvn test
就是和生命周期:default
中的阶段:test
相连,会执行default
生命周期中阶段:test
之前所有的阶段(包括阶段:test
)mvn clean deploy site-deploy
命令涉及三个生命周期:生命周期:clean
,阶段:clean
生命周期:default
,阶段:deploy
生命周期:site
,阶段:site-deploy
目标
Maven
的核心包仅仅3MB
,实际的功能都是由 插件提供的(当Maven
需要的时候,就去远程仓库下载),也就是说上面的【生命周期】、【阶段】都是抽象的,不具备任何实际功能。由插件提供的功能称为goal
,通过绑定在 Maven
的【阶段】上,就能使得 Maven
在执行对应阶段时自动触发绑定的所有**goal**
。
【生命周期】,【阶段】、【插件目标 (goal) 】的关联关系如下所示:
可能有的同学想知道,为什么我下载安装【Maven】后没做任何设置都能正常使用呢?实际上是因为【Maven】默认会自带一些插件 并 已默认绑定到一些阶段上。举个例子(实际上这只是一部分,更多的可以查看官网):
clean生命周期 | |
---|---|
阶段:clean |
插件:clean - 目标:clean |
default生命周期 | |
process-resources |
插件:resources - 目标:resources |
compile |
插件:compiler - 目标:compile |
process-test-resources |
插件:resources - 目标:testResources |
test-compile |
插件:compiler - 目标:testCompile |
test |
插件:surefire - 目标:test |
package |
插件:jar - 目标:jar 或插件:rar - 目标:rar 或插件:war - 目标:war (其他的没列出来) |
install |
插件:install - 目标:install |
deploy |
插件:deploy - 目标:deploy |
site生命周期 | |
site |
插件:site - 目标:site |
site-deploy |
插件:site- 目标:deploy |
实战
PS D:\workspace\present\RookieMaven> mvn verify
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------< com.codeleven.oa:RookieMaven >--------------------
[INFO] Building RookieMaven 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ RookieMaven ---
[WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\workspace\present\RookieMaven\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ RookieMaven ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
[INFO] Compiling 1 source file to D:\workspace\present\RookieMaven\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ RookieMaven ---
[WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\workspace\present\RookieMaven\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ RookieMaven ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
[INFO] Compiling 1 source file to D:\workspace\present\RookieMaven\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ RookieMaven ---
[INFO] Surefire report directory: D:\workspace\present\RookieMaven\target\surefire-reports
我们可以看到maven-resources-plugin:2.6:resources
、maven-compiler-plugin:3.1:compile
、maven-resources-plugin:2.6:testResources
等等。这里面的...:resources
、...:compile
、...:testResources
等等就是每个生命周期内的阶段。
插件绑定
如果想了解插件在哪个时刻运行,那么一定得知道插件绑定在【Maven】的哪个阶段。
默认绑定关系查看
使用命令:
mvn help:describe -Dplugin='org.springframework.boot:spring-boot-maven-plugin:2.0.6.RELEASE' -Ddetail
我们通过输出信息中,可以看到下面的绑定关系:
spring-boot:repackage
Description: Repackages existing JAR and WAR archives so that they can be
executed from the command line using java -jar. With layout=NONE can also
be used simply to package a JAR with nested dependencies (and no main
class, so not executable).
Implementation: org.springframework.boot.maven.RepackageMojo
Language: java
Bound to phase: package
可以看到 插件:spring-boot - 目标:repackage
已经Bound to phase: package
。
自定义绑定关系
咱们可以通过在<plugin>
元素里面添加<executions>
元素:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.6.RELEASE</version>
<executions>
<execution>
<!-- 指定这个插件想要绑定的阶段 -->
<phase>verify</phase>
<!-- 指定这个插件生效的功能(目标) -->
<goals>
<goal>repackage</goal>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
当Maven
执行到verify
这个阶段时,就会运行这个插件。
插件配置
命令行插件配置
很多插件目标的参数都支持命令行配置,用户可以在Maven
中使用-D
参数,并伴随一个参数键=参数值
的形式来配置插件。例如测试插件,maven-surface-plugin
提供了一个maven.test.skip
的参数:
mvn install -Dmaven.test.skip=true
那么在执行install
阶段过程中,会跳过测试环节。
POM中全局插件配置
若想全局配置插件属性,需要在<plugin>
的层级里添加元素<configuration>
:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.6.RELEASE</version>
<!-- 在<plugin>元素下直接添加 <configuration> 即可配置全局属性 -->
<configuration>
<finalName>最终包名</finalName>
<workingDirectory>工作目录</workingDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
POM中局部插件配置
若想局部配置插件属性,需要在<plugin>
的层级里添加元素<configuration>
:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.6.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
<goal>build-info</goal>
</goals>
<!-- 在<execution>元素下直接添加 <configuration> 即可配置局部属性 -->
<!-- 这个局部配置属性仅对当前<execution>进行配置 -->
<configuration>
<finalName>最终包名</finalName>
</configuration>
</execution>
</executions>
</plugin>
插件仓库
插件的远程仓库也需要配置,maven默认配置了远程的插件仓库:
<pluginRepositories>
<pluginRepository>
<id>central</id>
<name>Maven Plugin Repository</name>
<url>http://repo1.maven.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
</pluginRepository>
</pluginRepositories>