Apache Maven是一个项目管理工具(包括项目构建,依赖管理,信息管理)。它基于POM(Project Object Model),可以为Java项目提供强大的管理功能。
构建工具指的是把构建过程自动化的工具,包含以下过程:
生成源代码(如果使用了代码生成工具) 生成文档,根据源代码 编译源代码 将编译后的代码打包为jar文件或zip文件 安装打包文件到本地仓库、远程仓库或中央仓库Maven生命周期(Build Lifecycle)就是对构建过程的抽象,也就是说Maven使用生命周期来完成项目的构建。但是,maven只定义了抽象的生命周期,具体的实现是由插件来完成的(类似于模板方法设计模式)。
Maven包含三套内置的生命周期:
周期 | 作用 |
---|---|
clean |
清理项目 |
default |
构建项目 |
site |
生成项目站点文档 |
每个生命周期都包含不同的阶段,这些阶段都是有顺序的,当你执行一个阶段时,处于该生命周期下的当前执行阶段之前的阶段都会被执行,以确保顺利的构建。三套生命周期分别包含以下阶段:
clean生命周期
阶段名称 |
作用 |
---|---|
|
执行一些清理前需要完成的工作 |
|
清理上一次构建生成的文件 |
|
执行一些清理后需要完成的工作 |
default生命周期
|
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
site生命周期
|
|
---|---|
|
|
|
|
|
|
|
|
插件目标(Plugin Goal)
插件能够为Maven提供不同的功能,而一个插件可能包含多个插件目标。比如,如下是插件 maven-dependency-plugin 包含的三个插件目标:
|
|
---|---|
|
|
|
|
|
|
命令中使用冒号(:)分隔插件和插件目标,比如
compiler:compile表示 maven-compiler-plugin 插件的 compile 目标。
插件绑定(Plugin Binding)
前面说过,Maven只是定义了抽象的生命周期,生命周期阶段具体执行的操作是由其绑定的插件目标实现的。也就是说插件目标有一下两种方式被执行:
通过绑定到生命周期阶段,而在生命周期阶段执行时被调用 通过直接调用的方式(也就是“plugin:goal”的方式)在生命周期阶段外执行
NOTE:一个插件目标可以绑定到多个生命周期阶段,一个生命周期阶段也能绑定多个插件。一个生命周期阶段绑定多个插件目标的情况,其执行顺序是按照POM文件中插件目标定义的顺序。
默认插件绑定
我们怎样才能够绑定插件目标到生命周期阶段呢?两种方式:
Maven内置默认绑定 在POM文件中自定义绑定
对于
default生命周期,Maven会根据不同的
packaging,绑定不同的插件目标。
Clean 生命周期绑定
|
|
---|---|
|
|
Default 生命周期绑定 - Packaging ejb/ejb3/jar/par/rar/war
|
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Site 生命周期绑定
|
|
---|---|
|
|
|
|
其他默认的插件目标绑定请参考Maven官方文档。
自定义绑定
自定义绑定可将一个插件目标绑定到任意构建生命周期阶段上。要实现自定义绑定,需要在
project >
plugins >
plugin中声明。
...
org.apache.maven.plugins
maven-source-plugin
2.1.1
attach-sources
verify
jar-no-fork
...
以上示例中,声明了maven-source-plugin(使用
groupId、
artifactId、
version指定)。然后在
如果没有指定
通过以上的配置,现在执行
mvn verify
将看到
maven-source-plugin的
jar-no-fork目标被执行。
插件配置
几乎每个插件都有可配置的参数,以满足不同的构建需求。
命令行插件配置
执行生命周期或插件目标时,如果某个插件目标被调用,那么就可以通过
-D{parameter}的形式指定参数的配置。如:
mvn myquery:query -Dquery.url=http://maven.apache.org
POM 文件全局配置
在
project >
build >
plugins >
plugin >
configuration中配置的参数,将在每一次执行该插件的时候起作用。
[...]
[...]
org.apache.maven.plugins
maven-compiler-plugin
3.5.1
[...]
[...]
以上配置了
maven-compiler-plugin插件使用 java 1.7 编译源代码,那么无论在
compile生命周期中被调用,还是手动调用该插件,都会使用 java 1.7。
POM 文件插件任务配置
在
project >
build >
plugins >
plugin >
executions >
execution >
configuration 中配置的参数,只在该任务被执行时有效。
命令行执行插件
执行
mvn -h
看到如下帮助信息:
$ mvn -h
usage: mvn [options] [] []
options:mvn 命令选项 goal(s):插件目标 phase(s):生命周期阶段
根据以上知识,如果执行以下命令:
mvn clean dependency:copy-dependencies package
那么,
clean阶段会首先执行(包括在它以前的阶段),然后是
dependency:copy-dependencies插件目标,最后
package阶段被执行(包括它之前的阶段)。而生命周期阶段被执行也就是插件目标被执行,所以整个命令最终就是不同的插件目标执行,然后完成了想实现的目标。
插件前缀解析
Maven中标识插件也是使用
groupId:artifactId:version,但是实例中命令行调用都只有一个前缀和目标,比如
dependency:copy-dependencies。
Maven允许使用插件前缀来映射
groupId:artifactId,Maven有多种方式来指定这种映射方式。
根据约定确定
默认情况下,Maven通过去除
artifactId上通过连字符连接的
maven和
plugin来确定插件前缀:
maven-${prefix}-plugin:官方插件使用的artifactId ${prefix}-maven-plugin:其他来源的插件(如 tomcat 插件:tomcat7-maven-plugin)
使用以上两种方式,Maven能够通过
artifactId的形式,自动确定插件前缀。这样你就能够使用
tomcat7作为前缀来调用 tomcat 插件的目标,如
tomcat7:run。
手动指定
可以在声明插件时手动指定插件前缀:
...
...
...
maven-plugin-plugin
2.3
...
somePrefix
现在可以使用
somePrefix前缀来使用插件了:
mvn somePrefix:goal
配置Maven搜索插件前缀
如果,每个人都自己指定插件前缀,那么每个人的配置都不一样,那么岂不麻烦。maven就是为了消除这些麻烦,所以使用约定优于配置的原则来构建。
所以,很多插件都自己指定了插件前缀。那么,Maven是如何解析这些前缀的呢?
这些映射关系都放在
groupId/maven-metadata.xml中,所以,Maven使用如下的方式解析插件前缀:
在${groupId}路径下,下载远程仓库的maven-metadata.xml到该路径,然后重命名为maven-metadata-${repoId}.xml。 合并${groupId}路径下的maven-metadata-local.xml,然后加载合并后的文件。 然后在合并后的元数据中查找插件前缀,如果没找到就在下一个插件组重复这一过程。
如下是Maven官方插件(
groupId为
org.apache.maven.plugins)路径下的
maven-metadata.xml文件的片段:
Apache Maven Clean Plugin
clean
maven-clean-plugin
Apache Maven Compiler Plugin
compiler
maven-compiler-plugin
Apache Maven Dependency Plugin
dependency
maven-dependency-plugin
可以看到,每个
plugin元素指定了
prefix和
artifactId,所以这个插件前缀就唯一确定了
groupId:artifactId,再结合声明插件时指定的
version信息,Maven就完成了插件的解析。
Maven默认会搜索如下两个
groupId下的插件:
org.apache.maven.plugins org.codehaus.mojo
如果,需要Maven搜索更多
groupId下的插件,那么需要在
settings.xml中配置
org.codehaus.modello
这样,Maven就会首先搜索
org.codehaus.modello下的插件前缀,如果没有找到,再搜索
org.apache.maven.plugins、
org.codehaus.mojo。也就是
groupId优先级高于Maven默认的。这样,可以使用这一机制来覆盖默认的插件前缀的解析。
总结
本文重点介绍了Maven中很重要的生命周期和插件的概念,能够帮助学习者从原理方面来理解Maven,加强学习的效果。