Maven 是基于项目对象模型 (POM project object model),可以通过一小段描述信息(配置)来管理项目的构建,报告和文档的软件项目管理工具,简单的说就是用来管理项目所需要的依赖且管理项目构建的工具。
Maven 官网:https://maven.apache.org
Maven 仓库:https://search.maven.org/search
maven 把项目的构建划分为不同的生命周期(lifecycle)。包括:
maven 中所有的执行动作(goal)都需要指明自己在这个过程中的执行位置,然后 maven 执行的时候,就依照过程的发展一次调用这些 goal 进行各种处理。
这个也是 maven 的一个基本调度机制。一般来说,位置稍后的过程都会依赖于之前的过程。当然,maven 同样提供了配置文件,可以依照用户要求,跳过某些阶段。
maven 使用如下几个要素来唯一定位某一个输出物:
groupId;artifactId;packaging;version。
maven在版本管理时候可以使用几个特殊的字符串 SNAPSHOT ,LATEST ,RELEASE 。比如"1.0-SNAPSHOT"。各个部分的含义和处理逻辑如下说明:
1. SNAPSHOT 如果一个版本包含字符串"SNAPSHOT",Maven就会在安装或发布这个组件的时候将该符号展开为一个日期和时间值,转换为UTC时间。例如,"1.0-SNAPSHOT"会在2010年5月5日下午2点10分发布时候变成1.0-20100505-141000-1。这个词只能用于开发过程中,因为一般来说,项目组都会频繁发布一些版本,最后实际发布的时候,会在这些snapshot版本中寻找一个稳定的,用于正式发布,比如1.4版本发布之前,就会有一系列的1.4-SNAPSHOT,而实际发布的1.4,也是从中拿出来的一个稳定版。
2. LATEST 指某个特定构件的最新发布,这个发布可能是一个发布版,也可能是一个snapshot版,具体看哪个时间最后。
3. RELEASE 指最后一个发布版
项目结构图:
parent
├─childA(model层)
│ └─pom.xml(jar)
├─childB(web层)
│ └─pom.xml(war)
└─pom.xml(pom)
com.ht
parent
1.0-SNAPSHOT
pom
childA
childB
childA 和 childB 的 pom.xml 都需要配置 parent,防止引入的包冲突 (如果不加 parent,会分别去编译他们引入的依赖,会重复引入包):
parent
com.ht
1.0-SNAPSHOT
4.0.0
childA
jar
parent
com.ht
1.0-SNAPSHOT
4.0.0
childB
war
com.module
childA
1.0-SNAPSHOT
parent 中加上 dependencyManagement,child 项目就可以继承 parent 项目的依赖,并且在 child 中可以不用加 version 了。
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
子项目直接引入 parent的依赖 就行
dependency 依赖关系中 Scope(范围)的作用:主要管理依赖的部署。
如果不显示执行
删除线格式 属性时,默认
。
scope 属性包括(5 个值):
详细可参考:https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope
maven 的依赖关系是有传递性的。如:A–>B,B–>C。但有时候,项目 A 可能不是必需依赖 C,因此需要在项目 A 中排除对 A 的依赖。在 maven 的依赖管理中,有两种方式可以对依赖关系进行,分别是可选依赖(Optional Dependencies)以及依赖排除(Dependency Exclusions)。
当一个项目 A 依赖另一个项目 B 时,项目 A 可能很少一部分功能用到了项目 B,此时就可以在 A 中配置对 B 的可选依赖。举例来说,一个类似 hibernate 的项目,它支持对 mysql、oracle 等各种数据库的支持,但是在引用这个项目时,我们可能只用到其对 mysql 的支持,此时就可以在这个项目中配置可选依赖。
配置可选依赖的原因:1、节约磁盘、内存等空间;2、避免license许可问题;3、避免类路径问题,等等
。
sample.ProjectB
Project-B
1.0
compile
true
假设以上配置是项目 A 的配置,即:Project-A --> Project-B。在编译项目 A 时,是可以正常通过的。
如果有一个新的项目 X 依赖 A,即:Project-X -> Project-A。此时项目 X 就不会依赖项目 B 了。如果项目 X 用到了涉及项目 B 的功能,那么就需要在 pom.xml 中重新配置对项目 B 的依赖。
当一个项目 A 依赖项目 B,而项目 B 同时依赖项目 C,如果项目 A 中因为各种原因不想引用项目 C,在配置项目 B 的依赖时,可以排除对 C 的依赖。
示例(假设配置的是 A 的 pom.xml,依赖关系为:A --> B; B --> C):
sample.ProjectB
Project-B
1.0
compile
sample.ProjectC
Project-C
当然,对于多重依赖,配置也很简单,参考如下示例:
项目 A–> 项目 B --> 项目 C --> 项目 D --> 项目 E
sample.ProjectB
Project-B
1.0-SNAPSHOT
sample.ProjectE
Project-E
dependency 中 type 默认为 jar 即引入一个特定的 jar 包。那么为什么还会有 type 为 pom 呢?
当我们需要引入很多 jar 包的时候会导致 pom.xml 过大,我们可以想到的一种解决方案是定义一个父项目,但是父项目只有一个,也有可能导致父项目的 pom.xml 文件过大。这个时候我们引进来一个 type 为 pom,意味着我们可以将所有的 jar 包打包成一个 pom,然后我们依赖了 pom,即可以下载下来所有依赖的 jar 包
org.springframework.boot
spring-boot-dependencies
${spring.boot.version}
pom
import
用户可以使用该类属性引用 POM 文件中对应元素的值。如 ${project.artifactId} 就对应了
元素的值,常用的 POM 属性包括:
${project.build.sourceDirectory}: 项目的主源码目录,默认为 src/main/java/
${project.build.testSourceDirectory}: 项目的测试源码目录,默认为 src/test/java/
${project.build.directory} : 项目构建输出目录,默认为 target/
${project.outputDirectory} : 项目主代码编译输出目录,默认为 target/classes/
${project.testOutputDirectory}:项目测试主代码输出目录,默认为 target/testclasses/
${project.groupId}:项目的 groupId
${project.artifactId}:项目的 artifactId
${project.version} : 项 目 的 v e r s i o n , 与 {project.version}:项目的 version, 与 project.version:项目的 version, 与 {version} 等价
p
r
o
j
e
c
t
.
b
u
i
l
d
.
f
i
n
a
l
N
a
m
e
:项目打包输出文件的名称,默认为
{project.build.finalName} : 项目打包输出文件的名称,默认为
project.build.finalName:项目打包输出文件的名称,默认为{project.artifactId}-${project.version}
例子:
UTF-8
2.1.6_RELEASE
1.8
1.8
不配置 Plugin 时,Maven 默认会使用以下插件。如果针对各个 plugin 有特殊配置的话,需要显示指定 plugin 和 属性配置。
其中的 build 标签描述了如何来编译及打包项目,而具体的编译和打包工作是通过 build 中配置的 plugin 来完成。当然 plugin 配置不是必须的,默认情况下,Maven 会绑定以下几个插件来完成基本操作。
plugin | function | life cycle phase |
---|---|---|
maven-clean-plugin | 清理上一次执行创建的 target 文件 | clean |
maven-resources-plugin | 处理资源文件 | resources,testResources |
maven-compiler-plugin | 编译 Java 代码 | compile、testCompile |
maven-surefire-plugin | 执行单元测试文件 | test |
maven-jar-plugin | 创建 jar | package |
maven-install-plugin | 清理上一次执行创建的 target 文件拷贝 jar 到本地的 maven 仓库 /repository 下面清理上一次执行创建的 target 文件 | install |
maven-deploy-plugin | 发布 ja | deploy |
maven-site-plugin | 生成文档 | site |
maven-site-plugin:将工程所有文档生成网站,生成的网站界面默认和apache的项目站点类似,但是其文档用doxia格式写的,目前不支持docbook,需要用其他插件配合才能支持。需要指出的是,在maven 2.x系列中和maven3.x的site命令处理是不同的,在旧版本中,用 mvn site 命令可以生成reporting节点中的所有报表,但是在maven3中,reporting过时了,要把这些内容作为 maven-site-plugin的configuration的内容才行。
src/main/java
true
**/*.xml
src/main/resources
true
**/*.properties
*.xml
*.dic
*.txt
src/main/resources
false
*.p12
maven-compiler-plugin
3.1
1.8
UTF-8
org.apache.maven.plugins
maven-resources-plugin
2.6
UTF-8
spring-boot-maven-plugin
当使用 SpringBoot 开发项目的时候,会使用到 spring-boot-maven-plugin 插件
Spring Boot Maven plugin 有 5 个 Goals:
命令 | 说明 |
---|---|
spring-boot:repackage | 默认 goal。在 mvn package 之后,再次打包可执行的 jar/war, 并将 mvn package 生成的软件包重命名为 *.original |
spring-boot:run | 运行 Spring Boot 应用 |
spring-boot:start | 在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理 |
spring-boot:stop | 在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理 |
spring-boot:build-info | 生成 Actuator 使用的构建信息文件 build-info.properties |
其中比较重要的命令是:
mvn package spring-boot:repackage
执行后会看到生成的两个 jar 文件,一个是 *.jar,另一个是 *.jar.original。
这是由于在执行上述命令的过程中,Maven 首先在 package 阶段打包生成 *.jar 文件;然后执行 spring-boot:repackage 重新打包
maven-source-plugin 提供项目自动将源码打包并发布的功能,在需要发布源码项目的 pom.xml 文件中添加如下代码即可:
org.apache.maven.plugins
maven-source-plugin
attach-sources
jar
执行 mvn install
,maven 会自动将 source install 到 repository 。
执行 mvn deploy
,maven 会自动将 source deploy 到 remote-repository 。
执行 mvn source:jar
,单独打包源码。
注意:在多项目构建中,将 source-plugin 置于顶层或 parent 的 pom 中并不会发挥作用,必须置于具体项目的 pom 中。
mvn -v, –version 显示版本信息;
mvn -V, –show-version 显示版本信息后继续执行Maven其他目标;
mvn -h, –help 显示帮助信息; mvn -e, –errors 控制Maven的日志级别,产生执行错误相关消息;
mvn -X, –debug 控制Maven的日志级别,产生执行调试信息;
mvn -q, –quiet 控制Maven的日志级别,仅仅显示错误;
mvn -Pxxx 激活 id 为 xxx的profile (如有多个,用逗号隔开);
mvn -Dxxx=yyy 指定Java全局属性;
mvn -o , –offline 运行offline模式,不联网更新依赖;
mvn -N, –non-recursive 仅在当前项目模块执行命令,不构建子模块;
mvn -pl, –module_name 在指定模块上执行命令;
mvn -ff, –fail-fast 遇到构建失败就直接退出;
mvn -fn, –fail-never 无论项目结果如何,构建从不失败;
mvn -fae, –fail-at-end 仅影响构建结果,允许不受影响的构建继续;
mvn -C, –strict-checksums 如果校验码不匹配的话,构建失败;
mvn -c, –lax-checksums 如果校验码不匹配的话,产生告警;
mvn -U 强制更新snapshot类型的插件或依赖库(否则maven一天只会更新一次snapshot依赖);
mvn -npu, –no-plugin-updates 对任何相关的注册插件,不进行最新检查(使用该选项使Maven表现出稳定行为,该稳定行为基于本地仓库当前可用的所有插件版本);
mvn -cpu, –check-plugin-updates 对任何相关的注册插件,强制进行最新检查(即使项目POM里明确规定了Maven插件版本,还是会强制更新);
mvn -up, –update-plugins [mvn -cpu]的同义词;
mvn -B, –batch-mode 在非交互(批处理)模式下运行(该模式下,当Mven需要输入时,它不会停下来接受用户的输入,而是使用合理的默认值);
mvn -f, –file 强制使用备用的POM文件; mvn -s, –settings 用户配置文件的备用路径;
mvn -gs, –global-settings 全局配置文件的备用路径;
mvn -emp, –encrypt-master-password 加密主安全密码,存储到Maven settings文件里;
mvn -ep, –encrypt-password 加密服务器密码,存储到Maven settings文件里;
mvn -npr, –no-plugin-registry 对插件版本不使用~/.m2/plugin-registry.xml(插件注册表)里的配置
用法:
mvn -DpropertyName=propertyValue clean package
如果pom.xml中不存在名为propertyName属性,它将被设置
如果pom.xml中已存在propertyName属性,其(propertyValue)值将会传递给参数
要发送多个变量,请使用多个空格分隔符加-D:
mvn -DpropA=valueA -DpropB=valueB -DpropC=valueC clean package
举例:
pom.xml
myDefaultTheme
执行以下命令:
mvn -Dtheme=halloween clean package
打包后的pom.xml文件内容已被指定的参数替换:
<properties>
<theme>halloweentheme>
properties>
指定的中,可以通过-P进行传递或者赋值
举例
pom.xml
如下:
<profiles>
<profile>
<id>testid>
...
profile>
profiles>
则触发profile中的配置的命令为:mvn test -Ptest
在譬如pom.xml
如下:
<profile>
<id>testid>
<activation>
<property>
<name>envname>
<value>testvalue>
property>
activation>
...
profile>
则触发profile中的配置的命令为:mvn test -Penv=test