能够拜访 这里 查看更多对于大数据平台建设的原创文章。

一. 先看看什么是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

备注:

  1. DemoController.class没有间接援用jarC中的G.class类,引入的A1.class在jarA中是存在的;
  2. 编译的目标只是把业务源代码编译成.class文件;
  3. 所以在我的项目在编译的时候不会报错。

3. 为什么运行期间报错:NoClassDefFoundError

我的项目部署胜利后,当接管到前端发动的一次申请,须要调用selectList接口查问数据时,会因为在我的项目依赖的jar包里找不到G.class类而报错,一个具体的流程如下图所示:

备注:

  1. 因为要调用jarA中A1.classhandleWrite办法;
  2. 然而jarC 1.2版本曾经没有G.class类;
  3. 所以在执行的时候会报错:NoClassDefFoundError

四. jar包抵触:NoSuchMethodError

1. jarC版本升级抛弃了G.class的method1

问题来了,jarC 版本升级,由1.1 版本 降级到 1.2后,G.class类的begin办法因为逻辑优化而不存在了,改为begin1

2. 编译期间为什么不报错

备注:

  1. DemoController.class没有间接援用jarC中的G.class,而引入的A1.class在jarA中是存在的;
  2. 编译的目标只是把业务源代码编译成class文件;
  3. 所以在我的项目在编译的时候不会报错。

3. 运行期间为什么会报错:NoSuchMethodError


备注:

  1. 因为要调用jarA中A1.classhandleWrite办法;
  2. 在执行jarA包里的A1.classhandleWrite办法时须要调用jarC包里的begin办法;
  3. 然而jarC 1.2版本里,G.classbegin办法曾经不存在了;
  4. 因而在执行的时候会报错:NoSuchMethodError

五. 总结

  1. jar包抵触是java开发中常常会遇见且有的时候要耗时很久能力解决的问题;
  2. Maven 我的项目中jar包抵触大部分都是这两种场景,只有在弄清楚jar包抵触产生的起因后,咱们才可能在遇见问题的时候卓有成效的去排查、解决;
  3. 能够借助相干工具去帮忙排查jar抵触起因(后边会以实例介绍解决思路):

    • 如 idea自带的Show Dependencies;
    • idea装置插件 Maven Helper,通过查看 Dependency Analyzer;
    • 通过命令行执行 mvn dependency:tree>temp/tree.txt,能够生成具备jar包依赖关系的文件。

欢送大家关注微信公众号浏览更多文章