《maven实战》 学习笔记
在maven出现之前,项目构建的生命周期就已经存在了,软件开发人员每天都在对项目:清理-编译-测试-部署。
maven的生命周期就是为了对所有的构建过程进行抽象和同意。
maven的生命周期包括了:项目的清理-初始化-编译-测试-打包-集成测试-验证-部署-站点生成等几乎所有的构建步骤。
maven的生命周期是抽象的,它几乎不参与任何实际的工作,在maven的设计中,实际任务都是交由插件来完成的。
maven拥有三套相互独立的生命周期。它们分别是
包含三个阶段
validate
initialize
generate-sources
process-source: 处理项目主资源文件。 一般来说,是对src/main/resources
目录内容进行变量替换等工作后,复制到项目输出的主classpath目录中。
generate-resources
process-resources
compile: 编译项目的主源码,一般来说,是对src/main/java
目录下的文件进行编译,并输出至主classpath目录中.
process-classes
generate-test-sources
process-test-sources:处理项目测试资源文件。 一般来说,是对src/test/resources
目录内容进行变量替换等工作后,复制到项目输出的测试classpath目录中。
generate-test-resources
process-test-resources
test-compile: 编译项目的测试源码,一般来说,是对src/test/java
目录下的文件进行编译,并输出至测试classpath目录中.
process-test-classes
test: 使用单元测试框架运行测试,测试代码不会被打包或部署。
pre-package
package: 接收编译好的代码,打包成可发布的格式。 如JAR
pre-integration-test
integration-test
post-integration-test
verify
install: 将包安装到maven本地仓库,供本地其它maven项目使用。
deploy:将包复制到远程仓库
pre-clean + clean
validate,initialize ,..... test
maven的核心仅定义了抽象的生命周期,具体的任务是交由插件完成的,插件以独立的构建形式存在。
对于插件本身,为了能够复用代码,它往往能够完成多个任务。
例如:maven-dependency-plugin
,它能够给予项目依赖做很多事情。
maven-dependency-plugin
有十多个目标,每个目标对应了一个功能,上述提到的功能,分别对应的插件目标:dependency:analyze, dependency:tree, dependency:list,
.
冒号前面是插件前缀,冒号后面是插件的目标。
dependcy对应的插件完整名称是:org.apache.maven.plugins:maven-dependecncy-plugin
maven的生命周期与插件相互绑定,用以完成实际的构建任务。
例如: 项目编译这一任务,它对应了default生命周期的compile阶段
,而maven-compiler-plugin
这一插件的compile
目标能够完成该任务。 因此将二者绑定,就能实现项目的编译目的。
为了能让用户不用任何配置就能构建maven项目,maven在核心的一些主要的生命周期绑定了很多插件的目标,当用户通过命令行调用生命周期阶段时,对应的插件目标就会执行相应的任务 。
执行mvn clean install 查看执行了哪些插件目标:
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ test-reports ---
[INFO] Deleting /Users/huaijian/workspaces/idea/_self_project/test-reports/test-reports/target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ test-reports ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/huaijian/workspaces/idea/_self_project/test-reports/test-reports/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ test-reports ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 11 source files to /Users/huaijian/workspaces/idea/_self_project/test-reports/test-reports/target/classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ test-reports ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ test-reports ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 3 source files to /Users/huaijian/workspaces/idea/_self_project/test-reports/test-reports/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ test-reports ---
[INFO] Surefire report directory: /Users/huaijian/workspaces/idea/_self_project/test-reports/test-reports/target/surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running TestSuite
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Configuring TestNG with: org.apache.maven.surefire.testng.conf.TestNG652Configurator@7e2d773b
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.117 sec
Results :
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ test-reports ---
[INFO] Building jar: /Users/huaijian/workspaces/idea/_self_project/test-reports/test-reports/target/test-reports-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ test-reports ---
[INFO] Installing /Users/huaijian/workspaces/idea/_self_project/test-reports/test-reports/target/test-reports-1.0-SNAPSHOT.jar to /usr/local/repositories/mvn_repo/cn/jhs/test-reports/1.0-SNAPSHOT/test-reports-1.0-SNAPSHOT.jar
[INFO] Installing /Users/huaijian/workspaces/idea/_self_project/test-reports/test-reports/pom.xml to /usr/local/repositories/mvn_repo/cn/jhs/test-reports/1.0-SNAPSHOT/test-reports-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.551 s
[INFO] Finished at: 2023-04-12T17:22:49+08:00
[INFO] ------------------------------------------------------------------------
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-source-pluginartifactId>
<version>3.0.0version>
<executions>
<execution>
<id>attach-sourceid>
<phase>verifyphase>
<goals>
<goal>jar-no-forkgoal>
goals>
execution>
executions>
plugin>
执行** mvn verify**就能看到如下输出:
[INFO] --- maven-source-plugin:3.0.0:jar-no-fork (attach-source) @ test-reports ---
将上一节的
行删除。
执行命令:mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin:3.0.0 -Ddetail
source:test-jar-no-fork
Description: This goal bundles all the test sources into a jar archive.
This goal functions the same as the test-jar goal but does not fork the
build, and is suitable for attaching to the build lifecycle.
Implementation: org.apache.maven.plugins.source.TestSourceJarNoForkMojo
Language: java
Bound to phase: package
完成插件和生命周期的绑定后,用户还可以配置插件目标的参数,进一步调整插件目标执行的任务,以满足项目需求。
如: maven-surefire-plugin提供了一个maven.test.skip参数,当其值为true时,就可以跳过执行测试。
$ mvn install -Dmaven.test.skip=true
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.0.0version>
<configuration>
<source>1.8source>
<target>1.8target>
configuration>
plugin>
不管是compile阶段的maven-compiler-plugin:compile
任务,
还是test-compile阶段的maven-compiler-plugin:testCompile
任务,
都使用该配置,基于jdk1.8进行编译。
maven-antrun-plugin为例,它有一个目标run,可以在maven中调用Ant任务。
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-antrun-pluginartifactId>
<version>1.3version>
<executions>
<execution>
<id>ant-validateid>
<phase>validatephase>
<goals>
<goal>rungoal>
goals>
<configuration>
<tasks>
<echo>i'm bound to validate phaseecho>
tasks>
configuration>
execution>
<execution>
<id>ant-verifyid>
<phase>verifyphase>
<goals>
<goal>rungoal>
goals>
<configuration>
<tasks>
<echo>i'm bound to verify phaseecho>
tasks>
configuration>
execution>
executions>
plugin>
执行命令:mvn verify
[INFO] --- maven-antrun-plugin:1.3:run (ant-validate) @ test-reports ---
[INFO] Executing tasks
[echo] i'm bound to validate phase
[INFO] Executed tasks
.....
.....
[INFO] --- maven-antrun-plugin:1.3:run (ant-verify) @ test-reports ---
[INFO] Executing tasks
[echo] i'm bound to verify phase
[INFO] Executed tasks
mvn help:describe -Dplugin=GROUPID:ARTIFACTID:VERSION
% mvn -h
usage: mvn [options] [<goal(s)>] [<phase(s)>]
options: mvn有20多个可选项,暂不表述。 mvn命令后面可以添加多个goal 和phase
为了简化配置和使用,如果插件是maven官方插件:即groupId:org.apache.maven.plugins,就可以省略groupId配置。
同样为了简化配置和使用,用户在没有指定插件版本的情况下,maven会自动化解析插件版本。
首先,在maven 超级POM为所有核心插件设定了版本。
超级POM 是所有maven项目的父POM.
如果用户使用插件时没有指定版本,且插件也不是核心插件,maven会去检查所有仓库的可用版本然后做出选择。
仓库元数据: groupId/artifactId/maven-metadata.xml
以maven-compiler-plugin为例,它的元数据:https://repo1.maven.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml
<metadata>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<versioning>
<latest>3.11.0latest>
<release>3.11.0release>
<versions>
<version>2.0-beta-1version>
<version>2.0version>
<version>2.0.1version>
<version>2.0.2version>
<version>2.1version>
<version>2.2version>
<version>2.3version>
<version>2.3.1version>
<version>2.3.2version>
<version>2.4version>
<version>2.5version>
<version>2.5.1version>
<version>3.0version>
<version>3.1version>
<version>3.2version>
<version>3.3version>
<version>3.5version>
<version>3.5.1version>
<version>3.6.0version>
<version>3.6.1version>
<version>3.6.2version>
<version>3.7.0version>
<version>3.8.0version>
<version>3.8.1version>
<version>3.9.0version>
<version>3.10.0version>
<version>3.10.1version>
<version>3.11.0version>
versions>
<lastUpdated>20230227075825lastUpdated>
versioning>
metadata>
Maven 遍历本地仓库和所有远程插件仓库,将该路径下的仓库元数据归并后,就能计算出latest 和release 的值。
在Maven 2中,插件的版本会被解析至latest。也就是说,当用户使用某个非 核心插件且没有声明版本的时候,Maven 会将版本解析为所有可用仓库中的最新版本,面 这个版本也可能是快照版。
前面讲到mvn 命令行支持使用插件前缀来简化插件的调用,
现在解释Maven 如何根据插件前缀解析得到插件的坐标。
插件前缀与groupld:artifactld是一一对应的,这种几配关系存储在仓库元数据中 。
与之 前提到的groupld/artifactld/maven-metadata.xml
不同,这里的仓库元数据为groupld/maven-metadate.xml,那么这里的groupld是什么呢?
Maven在解析捕件仓库元数据的时候,会默认使用org apache.maven.plugins
和org.codehaus.mojo
两个groupld。也可以通过配置settings.xml 让 Maven 检查其他 groupld 上的插件仓库元数据:
基于该配置,Maven 就不仅仅会检查org/apache/maven/plugins/maven-metadata.xml
和 org/codehaus/mojo/maven-metadata.xml
还会检查com/your/plugins/maven-metadata.xml
以https://repo1.maven.org/maven2/org/apache/maven/plugins/maven-metadata.xml为例:
<metadata>
<plugins>
<plugin>
<name>Apache Maven ACR Pluginname>
<prefix>acrprefix>
<artifactId>maven-acr-pluginartifactId>
plugin>
<plugin>
<name>Apache Maven Ant Pluginname>
<prefix>antprefix>
<artifactId>maven-ant-pluginartifactId>
plugin>
....
plugins>
metadata>