title: Maven 那点不为人知的事
date: 2020/11/24 03:48
1、Maven 构建的生命周期
Maven 将一个整体任务划分为一个个的阶段,按顺序依次执行,也可以指定该任务执行到中间的某个阶段结束。执行命令为 mvm 阶段名
(例如:mvn pre-clean)
clean 生命周期
包含以下阶段(pashe):
- pre-clean:执行一些清理前需要完成的工作。
- clean:清理上一次构建生成的文件。
- post-clean:执行一些清理后需要完成的工作。
default 生命周期
包含以下阶段,default 生命周期定义了真正构建时所需要执行的所有步骤,它是所有生命周期中最核心的部分:
生命周期阶段 | 描述 |
---|---|
validate | 检查工程配置是否正确,完成构建过程的所有必要信息是否能够获取到。 |
initialize | 初始化构建状态,例如设置属性。 |
generate-sources | 生成编译阶段需要包含的任何源码文件。 |
process-sources | 处理源代码,例如,过滤任何值(filter any value)。 |
generate-resources | 生成工程包中需要包含的资源文件。 |
process-resources | 拷贝和处理资源文件到目的目录中,为打包阶段做准备。 |
compile | 编译工程源码。 |
process-classes | 处理编译生成的文件,例如 Java Class 字节码的加强和优化。 |
generate-test-sources | 生成编译阶段需要包含的任何测试源代码。 |
process-test-sources | 处理测试源代码,例如,过滤任何值(filter any values)。 |
test-compile | 编译测试源代码到测试目的目录。 |
process-test-classes | 处理测试代码文件编译后生成的文件。 |
test | 使用适当的单元测试框架(例如JUnit)运行测试。 |
prepare-package | 在真正打包之前,为准备打包执行任何必要的操作。 |
package | 获取编译后的代码,并按照可发布的格式进行打包,例如 JAR、WAR 或者 EAR 文件。 |
pre-integration-test | 在集成测试执行之前,执行所需的操作。例如,设置所需的环境变量。 |
integration-test | 处理和部署必须的工程包到集成测试能够运行的环境中。 |
post-integration-test | 在集成测试被执行后执行必要的操作。例如,清理环境。 |
verify | 运行检查操作来验证工程包是有效的,并满足质量要求。 |
install | 安装工程包到本地仓库中,该仓库可以作为本地其他工程的依赖。 |
deploy | 拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程。 |
site 生命周期
Maven Site 插件一般用来创建新的报告文档、部署站点等。包含以下阶段:
- pre-site:执行一些在生成项目站点之前需要完成的工作。
- site:生成项目站点文档。
- post-site:执行一些在生成项目站点之后需要完成的工作。
- site-deploy:将生成的项目站点发布到服务器上。
2、阶段与插件的关系
阶段相当于观察者模式中的消息发布者,而各个插件是消息订阅者,当用户执行某个命令,触发到了某个阶段的时候,他就会通知插件,插件就会执行它配置好的目标(goal)。
示例:SpringBoot 插件
org.springframework.boot
spring-boot-maven-plugin
他属于 default 生命周期,绑定到的阶段为 package 阶段,该插件的默认目标为 repackage。
SpringBoot 插件的配置
org.springframework.boot
spring-boot-maven-plugin
repackage
package
repackage
${start-class}
3、依赖管理 标签
compile
默认 scope,编译、测试、运行都需要这个依赖。
provided
编译、测试时需要,运行和打包不需要。
scope 为 provided 的依赖一般是由 JDK 或者容器(例如 Tomcat)所提供的 jar 包,为了编译通过而添加的,
runtime
编译时不需要,运行、测试、打包时需要。
一般用于运行时通过反射调用的类,例如数据库驱动。
test
编译、运行、打包时不需要,测试时需要。
system & systemPath
直接通过系统路径进行引用的 jar 包,编译、测试、运行都需要这个依赖。
org.mozilla.intl
chardet
1.0
system
${project.basedir}/src/main/resources/lib/chardet-1.0.jar
import
将其他 pom 文件中的 dependencyManagement 引入到当前 pom 文件中的 dependencyManagement。
一般父 pom 文件主要就是做依赖管理的,但是 maven 只支持单继承,但是我们假如想要引入多个依赖管理就需要 import 这个 scope 了。
其他 —— 依赖是否传递 optional
当项目自身被依赖时,标注依赖是否传递。用于连续依赖时使用。
假设我有一个 base 项目,web 项目需要引用他,base 项目中引入了 spring-context.jar,但是使用了 optional 域,那么当 web 项目引用 base 打成的 jar 包的时候,并不会引入 spring-context 这个 jar 包。
org.springframework
spring-context
true
4、依赖冲突
一个项目A,通过不同依赖传递路径依赖于X,若在不同路径下传递过来的X版本不同,那么A应该导入哪个版本的X包呢?
当出现依赖冲突的时候,maven 会根据以下 3 种原则来进行解决:
1)路径近者优先原则
如果依赖路径的长度不同,则“短路优先”:
- A —>B —>C —>D —> E —> X(version 0.0.1)
- A —>F —>X(version 0.0.2)
则 A 依赖于 X(version 0.0.2)。
org.springframework
spring-context
4.2.4.RELEASE
org.apache.struts
struts2-spring-plugin
2.3.24
org.springframework
spring-beans
4.2.5.RELEASE
2)先声明优先原则
- A —> E —> X(version 0.0.1)
- A —> F —> X(version 0.0.2)
则在项目 A 的中,E、F 哪个先引入则 A 依赖哪条路径的 X。
org.springframework
spring-context
4.2.4.RELEASE
org.apache.struts
struts2-spring-plugin
2.3.24
3)排除原则
org.apache.struts
struts2-spring-plugin
2.3.24
org.springframework
spring-beans
5、setting.xml 文件解析
1)localRepository
2)proxy
3)servers
4)mirror
5)profile
6)activeProfiles
强烈建议看下这篇文章,这篇文章对 setting.xml 中的每一个配置项都进行了详细的说明。
快照版(SNAPSHOT) & 发布版(RELEASE)
maven 中的仓库分为两种,snapshot 快照仓库和 release 发布仓库。
快照仓库用于保存开发过程中的不稳定版本,发布仓库则是用来保存稳定的发行版本。
定义一个组件/模块为快照版本,只需要在 pom 文件中在该模块的版本号后加上 -SNAPSHOT
即可(注意这里必须是大写)。
release 版本不允许修改,每次对 release 版本修改和发布必须提升版本号。而 snapshot 一般是开发过程中的迭代版本,snapshot 更新时不需要提升版本号,从而引用的项目可以不修改版本号自动下载构建。
6、pom.xml 解析
4.0.0
com.ouyang.maven
maven-test
0.0.1-SNAPSHOT
jar
maven-test
http://maven.apache.org
distcentral
libs-release
http://elb-791125809.cn-northwest-1.elb.amazonaws.com.cn:5336/artifactory/libs-release
distsnapshots
libs-snapshot
http://elb-791125809.cn-northwest-1.elb.amazonaws.com.cn:5336/artifactory/libs-snapshot
UTF-8
junit
junit
3.8.1
test
org.apache.maven.plugins
maven-source-plugin
3.0.1
package
jar-no-fork
src/main/resources
*.properties
*.yaml
src/main/resources
true
bootstrap.properties
bootstrap.yaml
application.properties
application-${profile.active}.properties
application.yaml
application-${profile.active}.yaml
super pom
所有的 POM 都继承自一个父 POM(无论是否显式定义了这个父 POM)。父 POM 也被称作 Super POM,它包含了一些可以被继承的默认设置。
Maven 使用 effective pom(指Super pom 加上工程自己的配置)来执行相关的目标,它帮助开发者在 pom.xml 中做尽可能少的配置,当然这些配置可以被方便的重写。
查看 Super POM 默认配置的一个简单方法是执行以下命令:mvn help:effective-pom
正是通过这个 super pom 才简化了我们的构建过程,这正是“约定优于配置”,开发者不需要再关心每一个配置细节。Maven 为工程提供了合理的默认行为。当创建 Maven 工程时,Maven 会创建默认的工程结构。开发者只需要合理的放置文件,而在 pom.xml 中不再需要定义任何配置。
7、mvn install 到仓库的文件结构
metadate.xml
发布版(RELEASE)jar 包的目录结构很简单,里面只有一个 jar 包和这个 jar 包所引用的 pom.xml,如果 maven 发现本地仓库有就不会再从远程仓库中获取。
但是快照版(SNAPSHOT)jar 包设计初衷就是为了在不改变版本号的前提下做快速迭代,所以它支持按照时间比对的方式来更新 jar,遵循如下逻辑:
- 检查
配置中的 updatePolicy (更新策略)的值,他支持的值有:always(总是更新)、daily (default,每天更新)、interval:X (X 为多少 min) 和 never(从不) - 当 updatePolicy 策略判断通过,尝试获取 remote metadata.xml
- 之后比较 local & remote metadata.xml 中时间戳,决定是否执行 download
为啥 clean 的时候要下载这个
可能是每次使用 mvn xxx
命令的时候都会保持本地仓库的 jar 包时最新的?
xxx.lastUpdate
这些文件表示 maven 曾经尝试从服务器上下载依赖但是并未成功,为了节省带宽,他在文件中写入的特定时间段内不会进行再次尝试,使用 -U (例如:mvn -U clean)可以强制使其进行下载,当然直接删除这个文件也是可以的。
_remote.repositories 文件
使用Maven管理项目时,如果连不到远程仓库,但是明明本地仓库有对应的jar包,此时还是报找不到对应的包的原因,是maven3.x版本在从远程仓库下载资源后,会生成对应的_remote.repositories文件,标示该资源的来源,如果你有这个文件_remote.repositories,那就不会访问本地了,必须远程上有才行,否则就会报错。
解决方法是将_remote.repositories文件删除,亲测有效
https://zhuanlan.zhihu.com/p/65916665
8、将 jar 包发布到 maven 仓库(私服)
mvn deploy:deploy-file -DgroupId=com.dist -DartifactId=gis-base-supermap -Dversion=1.0.3-SNAPSHOT -Dpackaging=jar -Dfile=D:/SRC_产品_Supermap/gis-server-root/gis-base-supermap/target/gis-base-supermap-1.0.3-SNAPSHOT.jar -Durl=http://elb-791125809.cn-northwest-1.elb.amazonaws.com.cn:5336/artifactory/libs-snapshot/ -DrepositoryId=distsnapshots -DpomFile=D:\SRC_产品_Supermap\gis-server-root\gis-base-supermap\pom.xml
没测试过这个命令,但我猜测应该和直接双击 deploy 一样:
这种方式不会将打包的 jar 包的依赖一起打到私服中,所以要使用下面的这个命令:
mvn clean package deploy -pl map3d-api,xxx -am
-pl 表示模块列表,“dgp-server-ars-api ”这里可以写多个模块其一操作,逗号隔开
-am 是会级联到所有依赖
9、maven 搜索 jar 包的顺序
1、本地仓库,如果本地仓库中含有 _remote.repositories 文件,则会去文件中写的远程仓库地址进行拉取;
2、maven settings profile中的repository;
3、pom.xml中profile中定义的repository;
4、pom.xml中的repositorys(定义多个repository,按定义顺序找);
5、mirror
参考文章
Maven 生命周期
maven中使用scope= import
Maven配置文件解析
*Maven之setting.xml解析
MAVEN snapshot快照和release发布库的区别、作用
Apache Maven Site Plugin概述
聊聊 maven 的 snapshot 和 metadata
maven-metadata.xml文件的作用
极客学院 maven 教程
附录
附1:
4.0.0
asia.banseon
banseon-maven2
jar
1.0-SNAPSHOT
banseon-maven
http://www.baidu.com/banseon
A maven project to study maven.
jira
http://jira.baidu.com/banseon
Demo
[email protected]
[email protected]
[email protected]
http:/hi.baidu.com/banseon/demo/dev/
HELLO WORLD
banseon
[email protected]
Project Manager
Architect
demo
http://hi.baidu.com/banseon
No
-5
Apache 2
http://www.baidu.com/banseon/LICENSE-2.0.txt
repo
A business-friendly OSS license
scm:svn:http://svn.baidu.com/banseon/maven/banseon/banseon-maven2-trunk(dao-trunk)
scm:svn:http://svn.baidu.com/banseon/maven/banseon/dao-trunk
http://svn.baidu.com/banseon
demo
http://www.baidu.com/banseon
......
......
Windows XP
Windows
x86
5.1.2600
mavenVersion
2.0.3
/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/
/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/
......
......
......
......
......
......
banseon-repository-proxy
banseon-repository-proxy
http://192.168.1.169:9999/repository/
default
......
org.apache.maven
maven-artifact
3.8.1
jar
test
spring-core
org.springframework
true
......
banseon-maven2
banseon maven2
file://${basedir}/target/deploy
banseon-maven2
Banseon-maven2 Snapshot Repository
scp://svn.baidu.com/banseon:/usr/local/maven-snapshot
banseon-site
business api website
scp://svn.baidu.com/banseon:/var/www/localhost/banseon-web