A good opportunity, I want to help female colleagues Maven resolve conflicts

A story of the most important causes of any

Any one job, the girls have absolute superiority. Not to mention the IT industry, in the department if there is a female ape that program is definitely meat and potatoes, cared for it.

Before one occasion, a sister encountered a problem first came, style suddenly becomes the picture above, and rallied around it, but the final result is not ideal, I still have to go into action (here a little bragging) .

Sister encountered a problem Jar package conflicts, an error message is Caused by: java.lang.ClassNotFoundException, see an error or is missing a Jar package, or is a conflict.

In fact, often encounter problems in the work of this conflict, such as: Caused by: java.lang.NoSuchMethodError exception information is a result of the conflict, want to solve the conflict will have to know where the conflict (like crap).

Most of them are using Maven to manage dependent Jar, today This article is to explain how to solve the conflict depend on Maven brings.


Maven readme

Maven is a tool for building and managing Java projects. For direction of Java, Maven almost every access and use. Of course there are other tools instead of Maven, such as Ant and Gradle.

Have contact with Grails build Java Web project before, to do it is to use Gradle dependency management. As for just when Ant is also working in some old projects have seen, almost never seen the back.

Maven documentation Address:https://maven.apache.org[1]

Using Maven allows us to quickly build a new project, and it is easy to integrate and manage multiple tripartite framework. When we need a framework can go to search the information of this framework, and then configure to your project can be.

Search address:https://mvnrepository.com [2]

For example, we want to use Spring Boot, in addition to obtaining dependent Spring version of the document, you can own to search, select the corresponding version, as shown below:

You can see the default Maven is dependent manner, simply copy the whole content dependency to pom.xml file in the project can be. Dependent on the right side there are many other ways, such as Gradle and so on.


Maven relies transfer

Under the main speaker today how to solve the problem Maven dependency management to do when Jar package conflicts resolved before the first under the basic knowledge to understand.

The figure shows the dependence of the transmission Maven, the first item is the Spring and B dependent Guava two frames. A project was then in turn depends on the item B, item A will therefore depend on Spring and Guava two frames.


Jar package selection logic dependent transfer

Dependent transfer will lead the project depends on many other versions of Jar, Jar how to choose the package of this situation?

There are two rules:

  • Different distances from the past priority

  • The same distance, the former priority

As shown below, the project dependency item A and item B, A and B, respectively, of the Guava dependent, but dependent on the level, the item B shallower level, it is preferred Guava18.0.

When the same distance when the preference will be defined in the foregoing, as shown, project A and project B respectively and Guava18.0 Guava15.0 dependent version of, the foregoing item A in order item B, We will give priority to Guava15.0 version.

By relying on transitivity often cause problems Jar package conflicts, such as under item A in FIG itself relied Guava15.0, and then rely on the item B, item B in the dependent Guava18.0, so that the project A will also depends Guava15 .0 and Guava18.0.

如果刚好用到了高版本不兼容低版本的方法和类时,就会出现选择错误,因为 Maven 会根据依赖树的深浅来选型浅的依赖,也就是 15.0。


冲突案例

下面就是一个典型的 Jar 包冲突问题,当一个 Jar 有多个版本的时候,就会出现冲突。

错误信息可以看到 com.google.common.collect.FluentIterable.concat 这个方法找不到,目前是从 guava-18.0.jar 中加载的,这种问题我们改怎么解决呢?

Description:
An attempt was made to call the method com.google.common.collect.FluentIterable.concat(Ljava/lang/Iterable;Ljava/lang/Iterable;)Lcom/google/common/collect/FluentIterable; but it does not exist. Its class, com.google.common.collect.FluentIterable, is available from the following locations:
    jar:file:/Users/yinjihuan/.m2/repository/com/google/guava/guava/18.0/guava-18.0.jar!/com/google/common/collect/FluentIterable.class
It was loaded from the following location:
    file:/Users/yinjihuan/.m2/repository/com/google/guava/guava/18.0/guava-18.0.jar


Action:
Correct the classpath of your application so that it contains a single, compatible version of com.google.common.collect.FluentIterable


解决思路之悬丝诊脉

找出冲突的 Jar,看看当前项目中依赖了哪几个版本。

  

Eclipse

在 Eclipse 中可以双击 pom 文件,进入 Dependency 视图,输入你要搜索的 jar 名称进行搜索,就可以看出当前项目中哪些框架依赖了你搜索的 jar,什么版本都能知道。

Idea

Idea 中可以安装 maven helper 插件来查看相关依赖信息,默认选中 Conflicts 会展示当前项目存在冲突的依赖,当然我们也可以直接查看树形的依赖关系去分析冲突。


Maven 命令

不用不借助于开发工具的插件,我们可以直接用 Maven 命令来查看当前项目的依赖关系,命令行进入到你要分析的项目目录下,执行下面的命令将分析结果保存到文件中:

mvn dependency:tree > tree.log

执行完之后依赖的信息结构如下:

搜索了下 guava,发现在 smjdbctemplate 中依赖了 18.0 版本,这个框架是我自己基于 jdbctemplate 封装的一个框架。


解决思路之察言观色

其实很明显,错误信息已经告诉我们 18.0 中找不到 concat 方法,所以 18.0 肯定是不能用的,通过前面的分析,找到了直接依赖 guava.18.0.jar 的是 smjdbctemplate,解决办法就是将 smjdbctemplate 中的 guava 排除掉。

<dependency>
  <groupId>com.github.yinjihuan</groupId>
  <artifactId>smjdbctemplate</artifactId>
  <version>1.1</version>
  <exclusions>
    <exclusion>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
    </exclusion>
  </exclusions>
</dependency>

还有就是根据依赖树的深浅度来判断当前项目依赖的是哪个版本,如下图:

18.0 是最浅的,肯定是依赖它,其实在 Eclipse 里面直接查看 Maven Dependencies 就可以指定当前项目依赖哪些框架和版本信息,如下图:

当我们排除掉 18.0 后再来看依赖的版本是 20.0,如下图:

根据依赖树的深浅度,20.0 和 19.0 都是一样的层级,但是 20.0 在 19.0 前面,所以优先选择 20.0 版本。

再来看项目中的 pom 文件,发现 swagger 的声明顺序在 apollo 的前面。

如果我们把顺序调整一下,那么就会依赖 19.0 的版本。


总结

通过我仔细耐心的讲解,妹子终于自己解决了遇到的问题,后面的事你们就猜去吧。????

这种问题其实无法避免,当你依赖的三方框架越多的时候,冲突的可能性就越大。碰到问题的时候沉下心来仔细分析,借助于工具帮助你排查问题。

当然我们在自己项目中去依赖三方的框架,也是要注意版本的问题,特别是对于多模块的项目,每个子模块都去依赖不同的版本,这样很容易出问题,一般建议在父 pom 中 dependencyManagement 来统一管理版本,子模块直接统一使用父 pom 中定义好的版本。

还有就是可以使用 optional 来设置可选依赖,比如说你要封装一个通用的模块 Common,这个模块中有很多通用的功能,项目 A 依赖只需要使用功能 A,项目 B 依赖只需要使用功能 B。

每个功能都依赖了三方的 Jar,这个时候如果你不做任何处理,只要依赖了你这个通用的模块 Common,那么也就会间接依赖这两个功能的第三方 Jar。

这个时候可以通过设置 optional=true 来解决这个问题,我依赖了你的通用模块 Common,如果我要使用 A 功能,那么我必须显示依赖 A 功能需要的三方依赖才可以。

参考资料

[1] maven: https://maven.apache.org/
[2] mvnrepository: https://mvnrepository.com/

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

发布了94 篇原创文章 · 获赞 4220 · 访问量 78万+

Guess you like

Origin blog.csdn.net/hollis_chuang/article/details/104368185