能够拜访 这里 查看更多对于 大数据平台建设 的原创文章。
一. 先看看什么是 Maven 的传递性依赖
Maven 的传递性依赖
应用 Maven 工具,带给开发者最直观的益处就是:
- 不必再去各个网站下载各种不同的 jar 包了,也不必思考它们之间的依赖关系;
- 只需把我的项目依赖的 jar 包信息配置在 pom 文件中,它就会帮咱们提供好一个 jar 包和该 jar 包所依赖的其它 jar 包。
举例解释
比方,在我的项目中引入 easyexcel 后:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.6</version>
</dependency>
咱们应用 Maven Helper 插件,查问依赖树:
能够看到:
- easyexcel 依赖 cglib,cglib 又依赖 asm;
- 因而 cglib 和 asm 这两个包也会被引进来。
通过查看 External Libraries 列表能够失去验证:
| 二. Maven 的最短门路准则和最先申明准则
思考一个问题,因为 Maven 的依赖性传递个性,如果有多个 jar 包同时都依赖一个 jar 包,且版本不一样的时候,如下图:
那么 Maven 该应用 jarC 1.1 的包还是 jarC 1.2 的包呢?
这时会遵循两个规定,别离是 最短门路准则 和最先申明准则。
最短门路准则
如上图:
- jarA -> jarC(1.1)
- jarB -> jarD -> jarC(1.2)
Maven 我的项目最终会应用 1.1 的 C。
最先申明准则
那么当最短门路一样的时候该怎么办?
这时就须要最先申明准则,且最先申明准则就是在最短门路雷同的时候失效,如下图所示:
由上图能够看出,依赖门路如下:
- jarA -> jarC(1.2)
- jarB -> jarC(1.1)
当初最短门路是一样的,则就须要看谁先申明的。
在工程的 pom.xml
里,能够看到是先引入的 jarA,那么依据规定,则 jarC(1.2) 失效,Maven 会应用 jarC(1.2) 来进行编译和打包。
三. jar 包抵触:NoClassDefFoundError
软件开发通常都是会有一直的版本迭代,如果:
- 在一个我的项目中同时会有多个 jar 包都依赖同一个 jar 包;
- 且都依赖的这个 jar 进行了版本升级,
则此时工程就有可能会产生 jar 包抵触,上面将通过图解举例介绍。
1. jarC 版本升级抛弃了 G.class
如果 jarC 版本升级,由 1.1 版本 降级到 1.2 后,G.class
因为被批改而不存在了:
2. 编译期间为什么不报错
咱们晓得,Maven 编译时会把业务代码编译成 class
文件。
比方上面这种场景,业务代码 DemoController.java
类引入了 jarA 中的 A1.class
,maven 编译时会将业务代码DemoController.java
类编译为DemoController.class
:
备注:
- DemoController.class 没有间接援用 jarC 中的 G.class 类,引入的 A1.class 在 jarA 中是存在的;
- 编译的目标只是把业务源代码编译成.class 文件;
- 所以在我的项目在编译的时候不会报错。
3. 为什么运行期间报错:NoClassDefFoundError
我的项目部署胜利后,当接管到前端发动的一次申请,须要调用 selectList 接口查问数据时,会因为在我的项目依赖的 jar 包里找不到 G.class
类而报错,一个具体的流程如下图所示:
备注:
- 因为要调用 jarA 中
A1.class
的handleWrite
办法; - 然而 jarC 1.2 版本曾经没有
G.class
类; - 所以在执行的时候会报错:
NoClassDefFoundError
。
四. jar 包抵触:NoSuchMethodError
1. jarC 版本升级抛弃了 G.class 的 method1
问题来了,jarC 版本升级,由 1.1 版本 降级到 1.2 后,G.class
类的 begin
办法因为逻辑优化而不存在了,改为begin1
:
2. 编译期间为什么不报错
备注:
- DemoController.class 没有间接援用 jarC 中的
G.class
,而引入的A1.class
在 jarA 中是存在的; - 编译的目标只是把业务源代码编译成
class
文件; - 所以在我的项目在编译的时候不会报错。
3. 运行期间为什么会报错:NoSuchMethodError
备注:
- 因为要调用 jarA 中
A1.class
的handleWrite
办法; - 在执行 jarA 包里的
A1.class
的handleWrite
办法时须要调用 jarC 包里的begin
办法; - 然而 jarC 1.2 版本里,
G.class
的begin
办法曾经不存在了; - 因而在执行的时候会报错:
NoSuchMethodError
。
五. 总结
- jar 包抵触是 java 开发中常常会遇见且有的时候要耗时很久能力解决的问题;
- Maven 我的项目中 jar 包抵触大部分都是这两种场景,只有在弄清楚 jar 包抵触产生的起因后,咱们才可能在遇见问题的时候卓有成效的去排查、解决;
-
能够借助相干工具去帮忙排查 jar 抵触起因(后边会以实例介绍解决思路):
- 如 idea 自带的 Show Dependencies;
- idea 装置插件 Maven Helper,通过查看 Dependency Analyzer;
- 通过命令行执行 mvn dependency:tree>temp/tree.txt,能够生成具备 jar 包依赖关系的文件。
欢送大家关注微信公众号浏览更多文章