1. 能做什么
构建、依赖管理、项目信息管理
2. 坐标
坐标是依赖管理的基础,通过坐标定位依赖的构件
<modelVersion>4.0.0</modelVersion>
<groupId>com.ibai.test</groupId>
<artifactId>test-maven</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Learning more about maven</name>
- modelVersion:当前POM模型的版本,对于Maven2和Maven3来说,只能是 4.0.0
- groupId: 当前项目隶属的实际项目,一般命名为
com.公司名.项目名
- artifactId:实际项目中的模块,一般命名为
项目名-模块名
- version:版本,一般分为快照版本和稳定版本
- packaging:Maven的打包方式,默认是jar
3. 依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>4.1.0</version>
<type>jar</type>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
<scope>compile</scope>
<optional>false</optional>
</dependency>
-
scope
-
传递性依赖
规律:
<1> 当第二直接依赖是compile
时,传递依赖的范围与第一直接依赖的范围一致
<2> 当第二直接依赖是test
时,不会有传递依赖
<3> 当第二直接依赖是runtime
时,传递依赖的范围与第一直接依赖范围一致,除了compile
<4> 当第二直接依赖是provided
时,只有第一直接依赖范围是provided
时,传递依赖范围是provided
,其他情况没有传递依赖。 依赖调解
比如有以下的传递性依赖
A->B->C->X(1.0)
A->D->X(2.0)
这时会使用第一个原则:路径最短原则
如果路径相同,则会使用第二个原则:声明顺序优先原则
-
optional
可选依赖不能传递,一般情况下不建议使用可选依赖
-
exclusions
不想使用传递性依赖,可能版本不稳定或其他原因,将传递性依赖排除后定义为直接依赖
-
归类依赖
将依赖的相同项目的不同模块的版本属性化
优化依赖
对于项目中直接使用的包,最好定义为直接依赖,便于控制
mvn dependency:list
mvn dependency:tree
mvn dependency:analyze
4. 仓库
统一存储所有Maven项目共享的构件叫仓库
- 仓库的布局
坐标与构件在仓库的路径转化关系是:
groupId/artifactId/version/artifactId-version.packaging
-
仓库分类
-
私服
-
从仓库解析依赖的机制
镜像
如果仓库X可以提供仓库Y存储的所有内容,那么可以认为X是Y的一个镜像。下面的配置是中央仓库的一个镜像
<mirror>
<id>maven-net-cn</id>
<name>Maven China Mirror</name>
<url>http://repo1.maven.org/maven2/</url>
<mirrorOf>central</mirrorOf>
</mirror>
5. 生命周期和插件
Maven的生命周期是一个抽象的概念,每个阶段都有对应的生命周期,生命周期本身不做什么事,所有的工作是由插件完成。
Maven有三套生命周期,相互独立,分别是clean
、default
、site
。
生命周期与插件的绑定实际是生命周期阶段和插件的目标(一个插件可以有多个目标)之间的绑定。
default
生命周期阶段与插件目标的绑定比较复杂,具体使用哪个插件的目标是与打包类型有关的。
上面这些生命周期阶段与插件目标的绑定是Maven的内置绑定,当然了开发人员也可以自定义绑定。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.1</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
- 插件配置
<1>命令行传参
用户可以通过命令行传参的方式调整插件的行为,比如不编译和执行测试用例
mvn install -Dmaven.test.skip=true
其中maven.test.skip
就是插件 maven-surfire-plugin
的参数
<2>POM全局配置
有些参数的值从项目创建到项目的发布都不会改变,或很少改变,对于这种情况,可以在POM中一次性配置好参数。所有基于该插件目标的任务,都会使用这些参数。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
通过上面的配置,不管是maven-complier-plugin
的 compile
目标还是 testCompiler
目标,都会基于 java 1.7
编译。
<3>POM中插件任务配置
也可以针对不同的任务(目标+生命周期阶段)配置不同的参数
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>ant-validate</id>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>I`m bound to validate phase.</echo>
</tasks>
</configuration>
</execution>
<execution>
<id>ant-verify</id>
<phase>verify</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>I`m bound to verify phase.</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
给插件 maven-antrun-plugin
的 run
目标,绑定不同的阶段,传递不同的任务参数
<4>查看插件的详情
https://maven.apache.org/plugins/index.html
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-compiler-plugin Ddetail=true
Name: Maven Compiler Plugin
Description: The Compiler Plugin is used to compile the sources of your
project.
Group Id: org.apache.maven.plugins
Artifact Id: maven-compiler-plugin
Version: 2.1
Goal Prefix: compiler
This plugin has 3 goals:
compiler:compile
Description: Compiles application sources
Implementation: org.apache.maven.plugin.CompilerMojo
Language: java
Bound to phase: compile
Available parameters:
compilerArgument
Sets the unformatted argument string to be passed to the compiler if fork
is set to true.
This is because the list of valid arguments passed to a Java compiler
varies based on the compiler version.
compilerArguments
Sets the arguments to be passed to the compiler (prepending a dash) if
fork is set to true.
.....
这里截取了一部分输出。
有两个字段需要说明: Goal Prefix
表示前缀,可以理解为插件名称的简写,Bound to phase
默认绑定的生命周期阶段
<5>从命令行调用插件
mvn -h
usage: mvn [options] [<goal(s)>] [<phase(s)>]
mvn 不仅可以调用生命周期阶段(mvn install),还可以直接调用插件的目标(mvn dependency:tree)。
有些插件的目标并不需要绑定到生命周期,比如 maven-help-plugin:describe
、maven-dependency-plugin:tree
- 插件解析
mvn help:system
这条命令的 help
指的是 maven-help-plugin
的前缀,system
是目标。怎么根据前缀找到对应的插件呢?
<1>插件仓库
和依赖构建一下,插件构建也有自己的仓库。以下是一个配置实例
<pluginRepositories>
<pluginRepository>
<id>pluginRepository-shuzun</id>
<url>http://ip:port/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<2>版本
如果插件没有指定版本,并且在超级POM中也没有指定,则会通过遍历本地库和远程库,归并元数据(groupId/artifactId/maven-metadata.xml),在Maven3中,使用release。一般最好指定版本。
<3>前缀
插件前缀与 groupId:artifactId 一一对应,这种对应关系存储在仓库的 groupId/maven-metadata.xml 元数据中。maven默认会检查groupId为 org.apache.maven.plugins
和 org.codehaus.mojo
,也可以通过配置 settings.xml
,让Maven检查其他的groupId上的插件仓库元数据
<pluginGroups>
<!-- pluginGroup
| Specifies a further group identifier to use for plugin lookup.
<pluginGroup>com.your.plugins</pluginGroup>
-->
</pluginGroups>
<4>默认的groupId
如果插件的groupId
是 maven.apache.maven.plugins
,可以省略不写 groupId
。
6.聚合与继承
- 聚合
一次构建多个模块,下面是一个聚合POM的样例
<modelVersion>4.0.0</modelVersion>
<groupId>com.ibai.test</groupId>
<artifactId>aggregator</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Learning more about maven</name>
<modules>
<module>./module1</module>
<module>./module2</module>
</modules>
有三点需要注意
<1> packaging 必须为 pom
,否则无法构建
<2> 聚合模块不需要主代码,只要一个pom文件就可以了
<3> module元素的值是模块目录名相对于当前pom文件的路径,一般与模块的 artifactId 保持一致
- 继承
实现复用
以下是一个实例
<modelVersion>4.0.0</modelVersion>
<groupId>com.ibai.test</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Learning more about maven -parent</name>
<modelVersion>4.0.0</modelVersion>
<artifactId>module3</artifactId>
<name>Learning more about maven - module1</name>
<parent>
<groupId>com.ibai.test</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
说明
<1> relativePath 指定父POM文件的路径,默认是 ../pom.xml
- 可继承的POM元素
groupId
versionId
description
organization:项目的组织信息
inceptionYear:项目的创始年份
url:项目的URL地址
developers
contributors
distributionManagement:项目的部署配置
issueManagement:项目的缺陷跟踪系统信息
ciManagement:项目的持续集成系统信息
scm:项目的版本控制系统信息
properties:自定义属性
dependencies
dependencyManagement
repositories
build
reporting
dependencyManagement
管理依赖,但不引入实际的依赖构建,一般让子模块继承父模块的 dependencyManagement
更灵活
约定优于配置
主代码路径,构建输出路径等信息都是在超级POM中定义了。反应堆
反应堆就是包含了各模块之间继承和依赖的关系,从而能够自动计算出合理的模块构建顺序
裁剪反应堆
-am,同时构建所列模块的依赖模块
-amd,同时构建依赖于所列模块的模块
-pl,构建指定的模块,多个模块之间用逗号分隔
-rf,从指定的模块回复反应堆