Maven插件
Maven插件
一、什么是生命周期
Maven的生命周期就是为了对所有的构建过程进行抽象和统一。这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤
几乎所有的项目构建都可以映射到这个生命周期上。每个构建步骤可以绑定一个或多个插件行为,而且Maven为大多数构建步骤编写并绑定了默认插件。
针对编译的插件有maven-compiler-plugin,针对测试的插件有maven-surefire-plugin
Maven定义的生命周期和插件机制一方面保证了所有Maven项目有一致的构建标准,另一方面又通过默认插件简化和稳定了实际项目的构件,此外还提供了足够的扩展空间,用户可以通过
配置现有插件或者自行编写插件来自定义构建行为
二、生命周期详解
maven拥有三套相互独立的生命周期,分别是clean、default、site,clean的目的是清理项目,default的目的是构建项目,site的目的是建立项目站点
每个生命周期都有一些阶段,这些阶段是按顺序执行的,并且单独执行某个生命周期不会影响其他生命周期。
clean生命周期:
pre-clean:执行清理前需要完成的工作
clean:清理上一次构建生成的文件
post-clean:执行一些清理后需要完成的工作
default生命周期:
validate
initialize
generate-sources
process-sources:处理项目主资源文件,一般来说,是对src/main/resources目录的内容进行变量替换等工作后,复制到项目输出的主classpath目录中
generate-resources
process-resources
compile:编译项目的主源码,一般来说,是编译src/main/java目录下的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目录下的Java文件至项目输出的测试classpath目录中
process-test-classes
test:使用单元测试框架运行测试,测试代码不会被打包或部署
prepare-package
package:接受编译好的代码,打包成可发布的格式,如JAR
pre-integration-test
integration-test
post-integration-test
verify
install:将包安装到Maven本地仓库,供本地其他Maven项目使用
deploy:将最终的包复制到远程仓库,供其他开发人员和Maven项目使用
site生命周期:
pre-site:执行一些在生成项目站点之前需要完成的工作
site:生成项目站点
post-site:执行一些在生成项目站点之后需要完成的工作
site-deploy:将生成的项目站点发布到服务器上
三、命令行与生命周期
$mvn clean:调用clean生命周期的clean阶段,实际执行为clean生命周期的pre-clean、clean阶段
$mvn test:调用default生命周期的test阶段,实际执行为default生命周期的validate、initialize等,直到test的所有阶段
$mvn clean install: 调用clean生命周期的clean阶段、default生命周期的install阶段,实际执行clean生命周期的pre-clean、clean阶段以及default生命周期从validate至install的所有阶段
$mvn clean deploy site-deploy:调用clean生命周期的clean阶段、default生命周期的deploy阶段以及site生命周期的site-deploy阶段,实际执行为clean生命周期的pre-clean、clean阶段,default生命周期的所有阶段,site生命周期的所有阶段
四、插件目标
对于插件本身,为了代码的复用,往往可以完成多个任务,如果为每一个功能都编写一个插件显然是不可取的,那么就将这些功能都集中到一个插件中,那么这每个功能就叫做插件的目标,例如maven-dependency-plugin有十多个目标,每个目标
对应一个功能,dependency:anlayze、dependency:tree、dependency:list。这是一种通用的写法,冒号前面是插件的前缀,冒号后面是插件的目标。
五、插件绑定
Maven的生命周期与插件相互绑定,用以完成实际的构建任务。具体而言,是生命周期的阶段与插件目标相互绑定,以完成某个特定的构建任务。例如项目编译这一任务,它对应了default生命周期的compile这一阶段,而maven-compile-plufgin这
一插件的conpile目标能够完成这项任务,因此,将它们绑定,就能实现项目的编译。
六、内置绑定
为了能让用户几乎不用任何配置就能够使用Maven构建项目, Maven为一些主要的生命周期阶段绑定了很多插件,用户通过命令行调用生命周期阶段的时候,对应的目标就会执行相应的任务。如clean声明周期的clean目标,默认绑定maven-clean-plugin
插件。用户可以执行mvn clean install命令,查看命令行输出,看项目构建过程中执行了哪些插件目标。
七、自定义绑定
除了内置绑定以外,用户还可以自己选择将某个插件目标绑定到生命周期的某个阶段,自定义绑定方式可以让Maven项目在构建过程中执行更多丰富特色的任务。
例如创建项目的源码jar包,内置的插件绑定关系中是没有涉及这一任务的,此时需要用户自己配置,maven-source-plugin可以帮我们完成该任务,他的jar-no-fork目标能够将项目的主代码打包成jar文件,可以将其绑定到default生命周期的verify阶段
1 <build> 2 <plugins> 3 <plugin> 4 <groupId>org.apache.maven.plugins</groupId> 5 <artifactId>maven-source-plugin</artifactId> 6 <version>2.1.1</version> 7 <executions> 8 <execution> 9 <id>attach-sources</id> 10 <phase>verify</phase> 11 <goals> 12 <goal>jar-no-fork</goal> 13 </goals> 14 </execution> 15 </executions> 16 </plugin> 17 </plugins> 18 </build>
执行mvn verify就能够在控制台看到如下信息:
--- maven-source-plugin:2.1.1:jar-no-fork<attach-source>@HelloWorld -
Building jar: E:\Workspace\HelloWorld\target\HelloWorld-sources.jar
当插件目标被绑定到不同的生命周期阶段的时候,其执行顺序会由生命周期阶段的先后顺序决定,如果多个目标被绑定到同一阶段,这些插件声明的先后顺序决定了目标的执行顺序
八、插件配置
1.命令行插件配置
很多插件目标的参数都支持从命令行配置,用户可以在Maven命令中使用-D参数,并伴随一个参数键=参数值的形式,来配置插件目标参数,例如,maven-surefire-plugin提供了一个maven.test.skip参数,当其值为true时,就会跳过执行测试。
在命令行输入:mvn install -Dmaven.test.skip=true
参数-D是java自带的,其功能是通过命令行设置一个Java系统属性,Maven简单的重用了该参数。
2.POM中插件全局配置
并不是所有的插件参数都适合从命令行配置,又下参数值从项目创建到项目发布都不会改变,对于这种情况,在POM中一次性配置显然比重复在命令行输入都要方便,用户可以在声明插件的时候,对此插件进行一个全局的配置。例如,我们通常会
需要配置maven-compile-plugin告诉它编译Java 1.5版本的源文件,生成与JVM 1.5兼容的字节码文件
1 <build> 2 <plugins> 3 <plugin> 4 <groupId>org.apache.maven.plugins</groupId> 5 <artifactId>maven-compile-plugin</artifactId> 6 <version>2.1</version> 7 <configuration> 8 <source>1.5</source> 9 <target>1.5</target> 10 </configuration> 11 </plugin> 12 </plugins> 13 </build> 14
这样,不管绑定到compile阶段的maven-compile-plugin:compile任务,还是绑定到test-compiler阶段的maven-compile-plugin:testCompiler任务,就都能够使用该配置,基于Java 1.5版本进行编译。
3.POM中插件任务配置
除了为插件配置全局的参数,用户还可以为某个插件任务配置特定的参数。例如,maven-autrun-plugin,它有一个目标run,可以用来在Maven中调用Ant任务。用户将maven-autrun-plugin:run绑定到多个生命周期阶段上,再加以不同的配置,
就可以让maven在不同的生命阶段执行不同的任务
1 <build> 2 <plugins> 3 <plugin> 4 <groupId>org.apache.maven.plugins</groupId> 5 <artifactId>maven-antrun-plugin</artifactId> 6 <version>1.3</version> 7 <executions> 8 <execution> 9 <id>ant-validate</id> 10 <phase>validate</phase> 11 <goals> 12 <goal>run</goal> 13 </goals> 14 <configuration> 15 <tasks> 16 <echo>I`m bound to validate phase.</echo> 17 </tasks> 18 </configuration> 19 </execution> 20 <execution> 21 <id>ant-verify</id> 22 <phase>verify</phase> 23 <goals> 24 <goal>run</goal> 25 </goals> 26 <configuration> 27 <tasks> 28 <echo>I`m bound to verify phase.</echo> 29 </tasks> 30 </configuration> 31 </execution> 32 </executions> 33 </plugin> 34 </plugins> 35 </build>
这段代码中,首先maven-autrun-plugin:run与validate阶段绑定,从而构成一个id为ant-validate的任务,插件全局配置中configuration元素位于plugin元素下面,而这里的cinfiguration元素则位于execution元素下面,表示这是特定任务的
配置,而非插件整体的配置,这个ant-validate任务配置了一个echo Ant任务,向命令行输出一段文字,表示该任务是绑定到validate阶段的。同样,第二个任务是绑定到verify阶段的,也向命令行输出一段文字,表示该任务绑定到verify阶段。
九、插件解析机制
1.插件仓库
与构建依赖一样,插件构件同样基于坐标存储在Maven仓库中,在需要的时候,Maven会从本地仓库寻找插件,如果不存在,则从远程插件仓库查找,找到后,再下载到本地仓库使用。
Maven会区别对待依赖远程仓库和插件远程仓库,当Maven需要的依赖在本地仓库不存在时,它会去配置的远程仓库中查找,可是当Maven需要的插件在本地不存在时,它就不会去这些远程仓库中找。
Maven的内置插件远程仓库:
1 <pluginRepositories> 2 <pluginRepository> 3 <id>central</id> 4 <name>Maven Plugin Repository</name> 5 <url>http://repo1.maven.org/maven2</url> 6 <layout>default</layout> 7 <snapshots> 8 <enabled>false</enabled> 9 </snapshots> 10 <releases> 11 <updatePolicy>never</updatePolicy> 12 </releases> 13 </pluginRepository> 14 </pluginRepositories>
一般情况下没中央仓库的插件完全能够满足我们的需要,只有在很少的情况下,项目的插件无法在中央仓库中找到,或者自己编写了插件,这个时候可以参考上述配置,在POM或settings.xml中加入其他插件仓库的配置。
2.插件默认的groupId
在配置POM的插件的时候,如果该插件是Maven官方插件,就可以省略groupId配置,如maven-compiler-plugin插件省略groupId时,Maven在解析的时候会自动默认groupId org.apache.maven.plugins补齐。
3.解析插件版本
同样是为了简化插件的配置和使用,在用户没有提供插件版本的情况下,Maven会自动解析插件版本。
首先,Maven在超级POM中为所有核心插件设定了版本,超级POM是所有Maven项目的父POM,所有项目都继承这个超级POM配置。如果用户使用的某个插件没有设定版本,而这个插件又不是核心插件,Maven会去检查所有仓库中的可用版本,
然后做出选择。以maven-compiler-plugin为例,它在中央仓库的仓库元数据为http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml:
<metadata> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <versioning> <latest>2.1</latest> <release>2.1</release> <versions> <version>2.0-beta-1</verison> <version>2.0</verison> <version>2.0.1</verison> <version>2.0.2</verison> <version>2.1</verison> </versions> <lastUpdated>20100102092331</lastUpdated> </versioning> </metadata>
Maven遍历本地仓库和所有远程插件仓库,将该路径下的仓库元数据归并后,就能计算出latest和release的值。latest表示仓库中该构件的最新版本,release表示最新的非快照版本。在Maven2中,插件会被解析至latest,而Maven3会解析到release
依赖Maven解析插件版本其实是不推荐的做法,例如,可能某个插件发布了一个新版本,而这个版本的行为与之前的版本发生了变化,这种变化可能导致项目构建失败,因此,使用插件的时候,应该一直显式的设定版本。
4.解析插件前缀
插件前缀与groupId:artifactId是一一对应的,这种匹配关系存储在仓库元数据中。主要的插件都位于http://repo1.maven.org/maven2/org/apache/maven/plugins/和http://repository.codehaus.org/org/codehaus/mojo/,相应的,
Maven在解析插件仓库元数据的时候会默认使用org.apache.maven.plugins和org.codehaus.mojo两个groupId。也可以通过配置settings.xml让Maven检查其他groupId上的插件仓库元数据
1 <settings> 2 <pluginGroups> 3 <pluginGroup>com.your.plugins</pluginGroup> 4 </pluginGroups> 5 </settings>
基于该配置,Maven就不仅仅会检查org/apache/maven/plugins/maven-metadata.xml和org/codehaus/mojo/maven-metadata.xml,还会检查com/your/plugins/maven-metadata.xml。
下面看一下插件仓库元数据的内容:
1 <metadata> 2 <plugins> 3 <plugin> 4 <name>Maven Clean Plugin</name> 5 <prefix>clean</prefix> 6 <artifactId>maven-clean-plugin</artifactId> 7 </plugin> 8 <plugin> 9 <name>Maven CompilerPlugin</name> 10 <prefix>compiler</prefix> 11 <artifactId>maven-compiler-plugin</artifactId> 12 </plugin> 13 <plugin> 14 <name>Maven DependencyPlugin</name> 15 <prefix>dependency</prefix> 16 <artifactId>maven-dependency-plugin</artifactId> 17 </plugin> 18 </plugins> 19 </metadata>
从上述代码中可以看出,maven-clean-plugin插件的前缀为clean,maven-compiler-plugin插件的前缀为compiler,maven-dependency-plugin插件的前缀为dependency。
当Maven解析到dependency:tree这样的命令后,它首先基于默认的groupId归并所有插件仓库的元数据org/apache/maven/plugins/maven-metadta.xml;其次检查归并后的元数据,找到对应的artifactId为maven-dependency-plugin;
然后结合当前元数据的groupId org.apache.maven.plugins;最后解析得到version,这时就得到了完整的插件坐标。如果org/apache/maven/plugins/maven-metadta.xml没有记录该插件的前缀,则接着检查其他groupId下的元数据,如
org/codehaus/mojo/maven-metadata.xml,以及用户自定义的插件组。如果所有元数据中都不包含该前缀,则报错。
浙公网安备 33010602011771号