温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java类加载器与类冲突怎么解决

发布时间:2022-01-14 10:49:11 来源:亿速云 阅读:622 作者:iii 栏目:大数据

这篇文章主要介绍了Java类加载器与类冲突怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java类加载器与类冲突怎么解决文章都会有所收获,下面我们一起来看看吧。

在同一个项目中,包含了一个类库的两个不同版本

这个时候,可能就会遇到奇怪的问题

  • 代码的逻辑不符合预期

  • 出现NoSuchMethodError

  • ...

先说结论,出现这些问题,不用怀疑,一定是当前使用的class版本和你预期的不一致。

这里我们以 apache 的 commons-codec类库来分析问题场景。

在实现一个功能的时候,你通过maven引入了这个库的依赖:

<dependency>

<groupId>commons-codec</groupId>

<artifactId>commons-codec</artifactId>

<version>1.10</version>

</dependency>

此时,在代码里使用了类库内处理Base64的一个类,有一个这样的实现

public static byte[] decodeBase64(String base64String) {
   return (new Base64()).decode(base64String);
}

然后没多久,系统中新增其它的功能,和其他系统对接的时候,引入了一个依赖。当我们高高兴兴的完成了任务,提交代码时,某天会遇到QA提了一个问题,XX功能现在不可用。

什么情况,WTF?

然后重跑功能,果不其然。什么情况。原来我们之前使用的commons-codec-1.10版本,并没有被使用,而是使用了com.springsource.org.apache.commons.codec-1.3.0版本。

什么情况?

我们在接入其他系统的时候,引入了一些依赖,而这其中他会依赖一个

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>com.springsource.org.apache.commons.httpclient</artifactId>
</dependency>

而他,会把上面的com.springsource.org.apache.commons.codec-1.3.0引进来。

此时,系统中就会有两个关于commons-codec的包。

而旧版本的对应Base64的类,只支持传入一个数组,不支持String

难道Maven这么傻,不会解决一下?

他会根据引入的版本,使用的maven的版本,从而选择是根据依赖声明的前后顺序或者是nearest来使用。但这个解决不了我们上面的问题,因为maven对于同一个groupId和artifactId才会使用上面这个依赖机制,所以相同的groupId和artifactId的依赖,会直接忽略,最终只使用一个。依赖树上可以看了出来:

Java类加载器与类冲突怎么解决

看上面的提示omitted for duplicate。而上面关于codec的依赖,是因为artifactId被换成了org.springsource.org.apache.commons,这样maven的机制就不会生效,导致项目里出现了两个codec的jar。而且,codec.jar虽然对于org.springsource这个指定的,虽然artifactId是这个,但里面的包名还是一样样的org.apache.commons,所以是相同于两个一模一样的Jar,只是版本不同。

这个时候,到了类加载器上场的时候了。类加载器在加载类,初始化的时候,会需要加载当前class依赖的类,此时,由于依赖低版本codec的class先被加载,从而导致低版本的codec被加载。

等后面再需要codec的地方又需要类的时候,此时虽然WebappClassloader可以子优先加载,对于不同的应用进行资源隔离,但是对于同一个应用内的相同package的类,是不会重复加载的。此时,有相同的请求到来时,从已经加载的资源中找到了低版本的codec,就直接用了,而这个类里没有我们要调用的方法,就出现了熟悉的NoSuchMethodError。

解决

问题了解清楚了,那该怎么解决呢,引入一个依赖的时候,总不能一个个的去查看jar的pom声明。

出现了上述问题时,如果不是使用maven管理依赖的,像之前SSH那种一下添加一堆jar到lib目录的时候,确定了对应的问题jar后,直接删除就好,简单直接。

如果是用maven管理依赖,就需要了解,是请把这小子带到这儿的。这个时候,使用maven的命令工具:

mvn dependency:tree

然后把结果生成到一个文件中,就可以查看引入冲突的jar是谁引进来的,查明真相后,就把依赖排除出去,

类似这样:

<dependency>
   <groupId>com.xxx</groupId>
   <artifactId>xxx</artifactId>
   <version>1.0.4</version>
   <exclusions>

<exclusion>
   <groupId>org.apache.commons</groupId>
   <artifactId>com.springsource.org.apache.commons.codec</artifactId>
</exclusion>


</exclusions>
</dependency>

关于“Java类加载器与类冲突怎么解决”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Java类加载器与类冲突怎么解决”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI