引言: Maven的生命周期是抽象的,实际行为都有插件来完成,插件以独立的构件形式存在。一个插件往往能够完成多个任务。
sequenceDiagram Maven命令 ->> 生命周期阶段: 激活 生命周期阶段 ->> 插件目标: 绑定
目录
[TOC]
生命周期
目的
为了对所有的构建过程进行抽象和统一。
作用
制定出通用的构建标准。抽象了构建的各个步骤,定义了它们的次序,但没有具体实现。
类比:设计模式中模板方法
插件机制
每个构建步骤都可以绑定一个或者多个插件行为,而且Maven为大多数构建步骤编写并绑定了默认插件。
详解
- Mavan有三套互相独立的生命周期,分别是clean、default和site。
- 周期有阶段组成,阶段是有顺序的,并且后面阶段依赖于前面的阶段。
clean
- 目的: 清理项目
- 包含阶段: pre-clean、clean、post-clean
default
- 目的: 构建项目
- 包含的重要阶段
- process-sources
处理项目主资源文件:通常是将<u>src/main/resources</u>目录的内容进行变量替换等工作后,复制到项目输出的主classpath(一般是target/classes下) - compile
编译项目的主代码:通常是将<u>src/main/java</u>目录的内容进行变量替换等工作后,复制到项目的主classpath(一般是target/classes下) - process-test-source
处理项目测试资源文件:通常是将<u>src/test/resources</u>目录的内容进行变量替换等工作后,复制到项目输出的测试classpath(一般是target/test-classes) - test-compile
编译项目的测试代码:通常是将<u>src/test/java</u>目录的内容进行变量替换等工作后,复制到项目的主classpath(一般是target/test-classes下) - test
使用单元测试框架运行测试,但测试代码不会被打包或者部署。 - package
接受编译好的代码,打包成可发布的格式,如JAR。 - install
将包安装到本地仓库,供本地其他Maven项目使用。 - deploy
将最终的包复制到远程仓库,供其他Maven项目使用。
- process-sources
site
- 目的: 建立和发布项目站点,基于POM所包含的信息,自动生一个友好站点,用于团队交流和发布项目信息。
- 包含阶段: pre-site、site、post-site、site-deploy
插件
插件目标
往往一个插件有多个目标,每个目标对应一个功能。
compiler:compile (compiler是插件前缀,commpile是插件目标。即:maven-compiler-plugin的compile目标)
插件绑定
生命周期的阶段 与 插件的目标 互相绑定,已完成某个具体的构件任务。
内置绑定
Maven为主要的生命周期阶段 绑定了 很多插件的目标;
eg:
生命周期阶段 | 插件目标 |
---|---|
clean | maven-clean-plugin:clean |
site | maven-site-plugin:site |
site-deploy | maven-site-plugin:deploy |
由于项目的打包类型会影响构建的具体过程,de***t生命周期与插件目标的绑定关系有项目打包类型决定。
注:de***t还有很多阶段没有绑定任何插件,因此也没有任何实际行为。
自定义绑定
自定义将某个插件的目标绑定到生命周期的某个阶段上,令在构建过程中执行更多更丰富的任务。
自定义绑定:创建项目的源码jar包。需在POM添加如下配置信息: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.1.1</version> <executions> <execution> <id>attach-sources</id> <!-- 任务ID --> <phase>verify</phase> <!-- 要绑定的阶段 --> <goals> <goal>jar-no-fork</goal> <!-- 执行的插件目标 --> </goals> </execution> </executions> </plugin> 验证: mvn verify 在日志中会发现该插件目标执行的信息,即证明配置已生效。
注: 如果你删除phase一行的配置,会发现执行依旧生效。 这种现象的原因是:很多插件在编写目标时已经定义了默认绑定阶段。
了解插件目标默认绑定的阶段:
使用maven-help-plugin阶段,具体运行命令如下:
mvm help:describe -Dplugin = org.apache.maven.plugins:maven-source-plugin:2.1.1 -Ddetail 注:查看打印信息中”Bound to phase“这一项即可知道。
当多个插件目标绑定到同一个阶段时,插件们的声明顺序决定了目标的执行顺序。
插件配置
命令行插件配置
在Maven命令中使用-D参数,并伴随 一个参数键=参数值 的形式,来配置插件目标的参数
mvn install -Dmaven.test.skip = true
注:参数-D是Java自带的,其功能是通过命令行设置一个Java系统属性,Maven重用了该参数,在准备插件时检查系统自带属性,变实现了插件参数的配置。
POM中插件全局参数配置
在POM中全局配置compiler插件,告诉项目编译指定JDK版本源文件,生成指定JDK版本字节码文件。 <plugin> <groupId> org.apache.maven.plugins </groupId> <artifactId> maven-compiler-plugin </artifactId> <configuration> <source> 1.8 </source> <target> 1.8 </target> </configuration> </plugin>
扩展: 在配置插件的时候,如果插件是Maven官方插件(即:groupId为 org.apache.maven.plugins ),可以省略groupId配置。Maven解析插件时会自动补全。 【并不推荐】
POM中插件任务配置
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.1.1</version> <executions> <execution> <id>attach-sources</id> <!-- 任务ID --> <phase>verify</phase> <!-- 要绑定的阶段 --> <goals> <goal>jar-no-fork</goal> <!-- 执行的插件目标 --> </goals> <!-- 插件任务配置如下 --> <configuration> <tasks> <echo> I'm bound to validate phase. </echo> </tasks> </configuration> </execution> </executions> </plugin>
命令行调用生命周期、插件
命令行执行Maven任务方式:
- 调用Maven的生命周期阶段 【最主要的方式】
【内部机制:mvn命令激活生命周期阶段,从而执行绑定在阶段上的插件目标。】
mvn clean (调用的是clean生命周期的clean阶段,实际执行阶段为clean生命周期的pre-clean、clean阶段)
- 调用插件目标
语法1: mvn [groupId]:[artifactId]:[version]:[插件目标]
为了方便在命令行直接运行插件,Maven引入插件前缀的概念,替换了原本的坐标。
语法2: mvn [插件前缀]:[插件目标]
mvn dependency:tree 注: dependency 就是 org.apache.maven.plugins:maven-dependency-plugin:2.1的插件前缀
思考:
- 什么Maven要支持从命令行调用插件目标?
答:主要是有些任务不太适合绑定在生命周期上,如描述构件信息(mvn help:descirbe -Dplugin=complier)、显示依赖树(mvn dependency:tree)等任务。- Maven引入插件前缀的概念,替换了原本的坐标。那Maven内部是如何解析插件前缀,获取插件的groupId、artifactId、version的呢? 请往下看。。。
插件解析机制
插件仓库
- 插件构件同样基于坐标存储在Maven仓库中。
- Maven会区别对待远程的依赖仓库和插件仓库,如当需要的插件不在本地仓库时,是不会去远程仓库查找的。
- Maven默认配置的插件中央仓库完全可以满足日常需要,但是也可以在POM或者setting.xml使用 <pluginRepositories> 和 <pluginRepository>配置自己的远程仓库,其子元素的配置同依赖的远程仓库配置完全一样。
解析插件version
首先Maven在超级POM中为所有核心插件设定了版本。
若用户在是使用某个插件时没有设定版本,怎么办呢?
- 若插件属于核心插件范畴,使用Maven超级POM中的版本。
- 若插件属于核心插件范畴,Maven会检查所有仓库中可用的版本,然后做出选择。使用Maven2插件版本会被解析至latest,使用Maven3插件版本会被解析至release.
基于如上规则,在使用插件时,强烈建议显示指定版本。
解析插件前缀
插件前缀是与坐标中的groupId:artifactId是一一对应的,其匹配关系存储在仓库元数据,这里的仓库元数据指的是仓库中的[groupId]/maven-metadate.xml文件,这里的<u>groupId默认使用org.apache.maven.plugins 和 org.codehaus.mojo两个groupId</u>,当然也可以通过setting.xml配置其他的groupId。
命令行mvn dependency:tree 的解析过程如下:
- 基于默认的一个groupId归并所有插件仓库的元数据,如org/apache/maven/plugins/maven-metadata.xml。
- 检查元数据,若能获得对应的插件的artifactId值,结合之前所说解析插件version的方法获得到插件version,就可以得到完整的插件坐标了。若没能或者,则检查其他groupId下元数据。直到得到结果。
插件信息
在线网站获取
- 基本主要的插件都来自Apache和Codehaus.
Apache插件信息
maven-help-plugin插件获取
语法1: mvn help:describe -Dplugin=[groupId]:[artifactId]:[version]
-Dgoal=[插件目标] -Ddetail
mvm help:describe -Dplugin = org.apache.maven.plugins:maven-source-plugin:2.1.1 -Ddetail
语法2: mvn help:describe -Dplugin=[插件前缀] -Dgoal=[插件目标] -Ddetail
mvm help:describe -Dplugin = compiler
总结
常用插件介绍:
https://www.cnblogs.com/crazy-fox/archive/2012/02/09/2343722.html
注意区分指定场景下仓库的元数据不同!!
插件前缀-插件 仓库元数据(即: [groupId]/maven-metadate.xml文件)
依赖/插件版本 仓库元数据(即: [groupId]/[artifactId]/maven-metadate.xml文件)