由一次jar包冲突来详述 Maven 依赖范围及依赖调节原则
2018-02-09 17:04
302 查看
这篇文章的缘由是刚来搭建的项目有jar包冲突,报下面这个错基本就是servlet-api包冲突无疑了
那怎么解决呢,一开始我想着找到 依赖关系,但是有可能A依赖B,B又依赖C,然后删掉多余的JAR包依赖。但是这些关联的包都是固定死的,pom文件都是从远程仓库拉的,不能改变,只能另找办法。
然后就是今天的主题,Maven 依赖范围及依赖调节原则
我们可以在根项目加一个Servlet-api的包,根据 路径最近者优先 ,maven只会加载我的Servlet-api包,其余的更远的就不加载了。其次,我在scope填provided,这样在项目真正运行时,maven不会自己加载Servlet-api包,而是相信容器会提供这个包,这样就不会跟容器(比如tomcat)造成jar包冲突。
下面是我看的一篇文章来的灵感,所以这本质还是一篇转载文章啦~
——————————————-转载分割线—————————————————————————————–
当在我们 POM 文件中配置 Maven 依赖的时候,常见的格式如下:
其中,groupId、artifactId 和 version 是 Maven 依赖的基本坐标,也是最重要的。其他的元素如 type 表示依赖的类型,默认为 jar ;scope 为依赖的范围,默认为 compile ;optional 用来标记依赖是否可选;exclusions 用来排除传递性依赖。
现在我们所要讲的依赖范围,正是其中 scope 元素所能选择的内容。在正式介绍依赖范围之前,我们需要知道一件事,那就是: Maven 项目的环境变量(classpath)有三种,分别为编译时用的环境变量、测试时用的环境变量和运行时用的环境变量 .而依赖范围就是用来控制依赖与这三种环境的关系的:
compile :编译依赖范围,此为默认值,对编译、测试和运行三种环境变量都有效。
test :测试依赖范围,仅对测试环境变量有效。
provided :已提供的依赖范围,对编译和测试环境变量都有效。
runtime :运行依赖范围,对测试和运行环境变量都有效。
system :系统依赖范围,对编译和测试环境变量都有效,但由于此依赖不是通过 Maven 仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。
import :导入依赖范围,并不会对上面的三种环境变量产生实际的影响。
如上图所示,此为 Maven 的直接依赖范围。除此之外,还有传递性依赖,那么何为传递性依赖呢?
举一个简单的例子,在默认依赖范围的情况下,如果项目 A 依赖 B,B 依赖 C,那么 A 就依赖 C,这时 A 与 C 就是传递性依赖的关系。而且我们称 A 对 B 的依赖为第一直接依赖,B 对 C 的依赖为第二直接依赖,以此类推。
至于为什么要强调 在默认依赖范围的情况下 ,则是传递性依赖也是有条件的,具体如下图所示:
如上图所示,此为 Maven 的直接依赖范围。除此之外,还有传递性依赖,那么何为传递性依赖呢?
举一个简单的例子,在默认依赖范围的情况下,如果项目 A 依赖 B,B 依赖 C,那么 A 就依赖 C,这时 A 与 C 就是传递性依赖的关系。而且我们称 A 对 B 的依赖为第一直接依赖,B 对 C 的依赖为第二直接依赖,以此类推。
至于为什么要强调 在默认依赖范围的情况下 ,则是传递性依赖也是有条件的,具体如下图所示:
观察上表,我们会发现:当第二直接依赖为 compile 时,则依赖关系以第一直接依赖为准;当第二直接依赖为 test 时,则没有依赖关系;当第二直接依赖为 provided 时,只有第一直接依赖也为 provided 时才有 provided 范围的依赖关系;当第二直接依赖为 runtime 时,除了第一直接依赖关系为 compile 时依赖范围为 runtime ,其他三种皆与第一直接依赖范围相同。
此外,有一些特殊的依赖情况,可能会造成一些困扰和问题,例如:
第一种依赖路径:A -> B -> C -> D(1.0)
第二种依赖路径:A -> B -> D(1.1)
其中 -> 表示依赖。如上面所示,项目 A 通过不同的路径都依赖到了项目 D,但 D 有两个不同的版本,这时怎么办?
对于这种情况,Maven 给出了一种解决方案,即: 路径最近者优先 。以上面的案例为例,第一种依赖路径的距离为 3 ,第二种依赖路径的距离为 2 ,因此这时就以第二种依赖路径为准,即依赖 D(1.1) 而不是 D(1.0) 。
不过,大家有没有想过:如果两种依赖路径的距离相同该怎么办呢?例如:
第一种依赖路径:A -> B -> D(1.0)
第二种依赖路径:A -> B -> D(1.1)
对于这种情况,在 Maven 2.0.9 之前是不能确定到底谁被依赖的,也就造成了依赖不确定性。但是在 Maven 2.0.9 之后,Maven 给出了解决方案,即: 第一声明优先 。简而言之,谁先声明就依赖谁。
最后,给出一些比较有用的 Maven 命令,通过这些 Maven 命令,我们能够快速了解 Maven 的依赖情况:
mvn dependency:list :查看 Maven 依赖列表,包直接依赖与传递性依赖。
mvn dependency:tree 查看 Maven 依赖树,可以清晰的看出依赖情况。
mvn analyze :分析 Maven 依赖的使用情况。
对于 Maven 这个优秀的构建工具、依赖管理工具、项目管理工具,值得我们花些时间去了解和掌握它!祝好。
温馨提示:此文的构思缘起于徐晓斌所著的《Maven实战》。
Caused by: java.lang.ClassCastException: org.springframework.web.SpringServletContainerInitializer cannot be cast to javax.servlet.ServletContainerInitializer
那怎么解决呢,一开始我想着找到 依赖关系,但是有可能A依赖B,B又依赖C,然后删掉多余的JAR包依赖。但是这些关联的包都是固定死的,pom文件都是从远程仓库拉的,不能改变,只能另找办法。
然后就是今天的主题,Maven 依赖范围及依赖调节原则
我们可以在根项目加一个Servlet-api的包,根据 路径最近者优先 ,maven只会加载我的Servlet-api包,其余的更远的就不加载了。其次,我在scope填provided,这样在项目真正运行时,maven不会自己加载Servlet-api包,而是相信容器会提供这个包,这样就不会跟容器(比如tomcat)造成jar包冲突。
下面是我看的一篇文章来的灵感,所以这本质还是一篇转载文章啦~
——————————————-转载分割线—————————————————————————————–
当在我们 POM 文件中配置 Maven 依赖的时候,常见的格式如下:
<project> ... <dependencies> <dependency> <groupId>...</groupId> <artifactId>...</artifactId> <version>...</version> <type>...</type> <scope>...</scope> <optional>...</optional> <exclusions> <exclusion> ... </exclusion> ... </exclusions> </dependency> ... </dependencies> ... </project>
其中,groupId、artifactId 和 version 是 Maven 依赖的基本坐标,也是最重要的。其他的元素如 type 表示依赖的类型,默认为 jar ;scope 为依赖的范围,默认为 compile ;optional 用来标记依赖是否可选;exclusions 用来排除传递性依赖。
现在我们所要讲的依赖范围,正是其中 scope 元素所能选择的内容。在正式介绍依赖范围之前,我们需要知道一件事,那就是: Maven 项目的环境变量(classpath)有三种,分别为编译时用的环境变量、测试时用的环境变量和运行时用的环境变量 .而依赖范围就是用来控制依赖与这三种环境的关系的:
compile :编译依赖范围,此为默认值,对编译、测试和运行三种环境变量都有效。
test :测试依赖范围,仅对测试环境变量有效。
provided :已提供的依赖范围,对编译和测试环境变量都有效。
runtime :运行依赖范围,对测试和运行环境变量都有效。
system :系统依赖范围,对编译和测试环境变量都有效,但由于此依赖不是通过 Maven 仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。
import :导入依赖范围,并不会对上面的三种环境变量产生实际的影响。
依赖范围(scope) | 编译环境变量有效 | 测试环境变量有效 | 运行环境变量有效 |
---|---|---|---|
compile | Y | Y | Y |
test | N | Y | N |
provided | Y | Y | N |
runtime | N | Y | Y |
system | Y | Y | N |
举一个简单的例子,在默认依赖范围的情况下,如果项目 A 依赖 B,B 依赖 C,那么 A 就依赖 C,这时 A 与 C 就是传递性依赖的关系。而且我们称 A 对 B 的依赖为第一直接依赖,B 对 C 的依赖为第二直接依赖,以此类推。
至于为什么要强调 在默认依赖范围的情况下 ,则是传递性依赖也是有条件的,具体如下图所示:
依赖范围(scope) | 编译环境变量有效 | 测试环境变量有效 | 运行环境变量有效 |
---|---|---|---|
compile | Y | Y | Y |
test | N | Y | N |
provided | Y | Y | N |
runtime | N | Y | Y |
system | Y | Y | N |
举一个简单的例子,在默认依赖范围的情况下,如果项目 A 依赖 B,B 依赖 C,那么 A 就依赖 C,这时 A 与 C 就是传递性依赖的关系。而且我们称 A 对 B 的依赖为第一直接依赖,B 对 C 的依赖为第二直接依赖,以此类推。
至于为什么要强调 在默认依赖范围的情况下 ,则是传递性依赖也是有条件的,具体如下图所示:
第一直接依赖 第二直接依赖 | compile | test | provided | runtime |
---|---|---|---|---|
compile | compile | —— | —— | runtime |
test | test | —— | —— | test |
provided | provided | —— | provided | provided |
runtime | runtime | —— | —— | runtime |
此外,有一些特殊的依赖情况,可能会造成一些困扰和问题,例如:
第一种依赖路径:A -> B -> C -> D(1.0)
第二种依赖路径:A -> B -> D(1.1)
其中 -> 表示依赖。如上面所示,项目 A 通过不同的路径都依赖到了项目 D,但 D 有两个不同的版本,这时怎么办?
对于这种情况,Maven 给出了一种解决方案,即: 路径最近者优先 。以上面的案例为例,第一种依赖路径的距离为 3 ,第二种依赖路径的距离为 2 ,因此这时就以第二种依赖路径为准,即依赖 D(1.1) 而不是 D(1.0) 。
不过,大家有没有想过:如果两种依赖路径的距离相同该怎么办呢?例如:
第一种依赖路径:A -> B -> D(1.0)
第二种依赖路径:A -> B -> D(1.1)
对于这种情况,在 Maven 2.0.9 之前是不能确定到底谁被依赖的,也就造成了依赖不确定性。但是在 Maven 2.0.9 之后,Maven 给出了解决方案,即: 第一声明优先 。简而言之,谁先声明就依赖谁。
最后,给出一些比较有用的 Maven 命令,通过这些 Maven 命令,我们能够快速了解 Maven 的依赖情况:
mvn dependency:list :查看 Maven 依赖列表,包直接依赖与传递性依赖。
mvn dependency:tree 查看 Maven 依赖树,可以清晰的看出依赖情况。
mvn analyze :分析 Maven 依赖的使用情况。
对于 Maven 这个优秀的构建工具、依赖管理工具、项目管理工具,值得我们花些时间去了解和掌握它!祝好。
温馨提示:此文的构思缘起于徐晓斌所著的《Maven实战》。
相关文章推荐
- 详述 Maven 依赖范围及依赖调节原则
- Maven的隐式依赖导致Jar包冲突的问题
- Maven Helper:查找和排除Jar包冲突的依赖关系
- Maven依赖jar包冲突常见的解决方法
- maven依赖(范围、传递、排除、冲突)
- [置顶] maven 命令和jar包依赖范围
- spring maven项目解决依赖jar包版本冲突方案
- 怎么spring security 和maven,spring,结合jar包冲突和依赖关系问题解决办法。
- maven依赖jar包时版本冲突的解决
- Maven依赖冲突之httpclient.jar包冲突异常分析
- maven中依赖版本冲突如何解决--四种方式(四种原则)
- 解决maven中servlet-api.jar和容器自带的servlet-api.jar的依赖冲突
- maven项目由于多个依赖中含有同一个jar包导致的冲突问题的解决办法
- 一点一点学maven(07)——maven依赖(范围、传递、排除、冲突)
- Maven查找依赖树,解决jar包冲突问题
- Maven 将Jar安装到本地仓库和Jar上传到私服及依赖范围控制
- Maven·依赖范围·传递依赖·依赖冲突
- 正确配置jstl的maven依赖,jar包冲突的问题终于解决啦
- 查lib下的jar来自哪个maven依赖(通过用于解决jar版本冲突)
- maven 检查jar依赖冲突和版本冲突 以及解决