Maven Dependency Scopes
- 参考文章:https://www.baeldung.com/maven-dependency-scopes,https://blog.csdn.net/kimylrong/article/details/50353161
Maven有6个依赖域。他们分别是Compile,Provided,Runtime,Test,System,Import。这里需要解释一下scope的依赖传递A–>B–>C。当前项目为A,A依赖于B,B依赖于C。知道B在A项目中的scope,那么怎么知道C在A中的scope呢?答案是:
当C是test或者provided时,C直接被丢弃,A不依赖C;
否则A依赖C,C的scope继承于B的scope。
- Compile
默认就是compile,什么都不配置也就是意味着compile。compile表示被依赖项目需要参与当前项目的编译,当然后续的测试,运行周期也参与其中,是一个比较强的依赖。打包的时候通常需要包含进去。具有传递依赖性,也就是父依赖的scope为compile,本项目中构建的所有流程中都会包括该依赖。
- Provided
provided意味着打包的时候可以不用包进去,别的设施(Web Container)会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。相当于compile,但是在打包阶段做了exclude的动作。一个典型的例子,web服务器一般在运行时提供了Servlet API。不具有传递依赖性,也就是父依赖的scope为provided,本项目中直接丢掉该依赖。
javax.servlet
servlet-api
2.5
provided
- Runtime
runntime表示被依赖项目无需参与项目的编译,不过后期的测试和运行周期需要其参与。与compile相比,跳过编译而已,说实话在终端的项目(非开源,企业内部系统)中,和compile区别不是很大。比较常见的如JSR×××的实现,对应的API jar是compile的,具体实现是runtime的,compile只需要知道接口就足够了。oracle jdbc驱动jar包就是一个很好的例子。另外runntime的依赖通常和optional搭配使用,optional为true。我可以用A实现,也可以用B实现。
# JDBC Driver就是一个很好的例子
mysql
mysql-connector-java
6.0.6
runtime
- Test
scope为test表示依赖项目仅仅参与测试相关的工作,包括测试代码的编译,执行。
# JUnit就是一个很好的例子
junit
junit
4.12
test
- System
从参与度来说,与provided相同,不过被依赖项不会从maven仓库抓,而是从本地文件系统拿,一定需要配合systemPath属性使用。
之前有做个一个图片视频的采集服务,项目是用maven管理的,并用docker部署。需要用到一个外部第三方包。所以我们需要把该本地包使用maven管理起来
thermogroup
infrared
1.0
system
${project.basedir}/lib/thermogroupsdk4java.jar
但是这里有一个问题,因为scope是system,所以使用maven打包的时候是不会把该本地jar包打包进去的。所以在打包docker的时候需要在dockerfile文件中显式的加进去。当时不想这么操作,通过配置maven插件的includeSystemScope参数为true,把本地包也打包进去。
org.springframework.boot
spring-boot-maven-plugin
true
- Import
scope为import标识这个依赖会被pom文件中的所有声明的依赖替代。Import只能结合dependencyManagement使用,用来做包管理和版本控制。最常见的案例是我们使用springboot,spring cloud的时候,我们使用dependencyManagement做一个大版本管理,后续子项目可以直接通过dependency声明使用的依赖而不需要指定版本(继承dependencyManagement pom文件中声明的依赖版本)。
org.springframework.boot
spring-boot-dependencies
2.1.10.RELEASE
pom
import
org.springframework.cloud
spring-cloud-dependencies
Greenwich.RELEASE
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.1.0.RELEASE
pom
import
Maven的Dependency机制
参考文档:https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
Maven依赖的管理是maven的核心功能,管理单个项目模块通常是简单的,但是对于复杂的项目通常涉及到上百个模块,maven的依赖管理就显得尤其重要。
Transitive Dependencies-依赖的传递性
由于依赖具有传递性,对于一个大一点的项目依赖的拓扑图就会变得越来越大,maven提供了以下几种方式来限制最终选择哪个依赖。
- Dependency mediation-依赖调节
当一个项目通过传递性依赖同一个库的不同版本时,会遵循就近原则。比如下面的这个依赖拓扑图,由于D2.0版本的库路径长度(A->B->C->D2.0)大于(A->E->D1.0)的路径长度,所以maven最终会依赖D1.0版本的库。
A
├── B
│ └── C
│ └── D 2.0
└── E
└── D 1.0
如果你需要显式的依赖D2.0,最佳实践是在自己的项目重声明依赖D2.0,这种它的路径就是(A->D2.0),会优先选择。通常我们最好显式的声明自己项目中使用的依赖,不要依靠依赖的传递性。
A
├── B
│ └── C
│ └── D 2.0
├── E
│ └── D 1.0
│
└── D 2.0
- Dependency management
参考上述对scope import的解读 - Dependency scope
参考上述对scope传递性的解读 - Excluded dependencies
显示的排除依赖
group-a
artifact-a
1.0
group-c
excluded-artifact
- Optional dependencies
可选依赖
sample.ProjectA
Project-A
1.0
compile
true
Maven的Profile的使用
在pom文件中声明profiles,可以设置默认profile.启动的时候以启动的分支为准。
local
local
true
test
test
prod
prod
我们可以在pom文件中通过${env}环境变量可以获取具体哪个分支,比如下面我想让不同的分支打包到harbor不同的镜像仓库,可以使用该环境变量。
dev2.out:8082
leather.${env}