我是靠谱客的博主 故意薯片,最近开发中收集的这篇文章主要介绍擎创技术流 | java多类加载器类冲突案例分析起因报错错误描述的意思是:分析原因:事发代码:分析:解决方案:,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

众所周知,jvm类加载机制采用双亲委派机制。但在有些框架中,常常为了提供某种形式的“隔离和沙盒”,自定义一种称为ChildFirst的类加载器,简单的说就是破坏了双亲委派,由自定义子类加载器优先加载类,而不是先委派给父加载器。由于同一个类可以在不同的类加载器中分别加载,使用ChildFirst机制,可以让类加载器形成一个“沙盒”,在程序中同时运行两个相同但不同版本的类。

但是,笔者遇到一个罕见的类加载冲突的案例,根因与ChildFirst机制有关。

起因

程序在flink平台上运行,将数据写入es,而某平台在开启了安全机制后,整个平台包括es都需要基于kerberos认证来访问。基于先验的结论,需要替换魔改的elasticsearch-rest-client,其中使用GSSAPI登录了kerberos,并基于SENGPO协议,通过http发送了类token,还有一个独立的线程对token进行刷新。由于是个private jar,在工程中使用非常不友好,所以考虑在打包job的时候用maven-shade-plugin排除原先依赖的elasticsearch-rest-client和elasticsearch-rest-highlevel-client,而将定制版jar放到flink/lib目录下。

报错

提交作业后,Task Manager报错退出如下:

java.lang.LinkageError: loader constraint violation: when resolving method "org.elasticsearch.client.RestClient.builder([Lorg/apache/http/HttpHost;)Lorg/elasticsearch/client/RestClientBuilder;" the class loader (instance of org/apache/flink/util/ChildFirstClassLoader) of the current class, org/apache/flink/streaming/connectors/elasticsearch6/Elasticsearch6ApiCallBridge, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for the method's defining class, org/elasticsearch/client/RestClient, have different Class objects for the type [Lorg/apache/http/HttpHost; used in the signature

错误描述的意思是:

org/apache/http/HttpHost同时在ChildFirstClassLoader和AppClassLoader中加载,在调用org.elasticsearch.client.RestClient.builder的时候传入org/apache/http/HttpHost实例的时候发现,方法签名(形参)中的类org/apache/http/HttpHost属于AppClassLoader,而实参的org/apache/http/HttpHost却属于ChildFirstClassLoader,造成了冲突。

分析原因:

基于下面这些事实:

  • job包中把HttpHost类打进去了。

  • flink的tm进程启动的时候会将hadoop下的httpcore.x.x.x.jar加到classpath

  • AppClassLoader负责加载classpath参数里面的类

  • ChildFirstClassLoader负责加载job包中的类

事发代码:

 

分析:

实参 httpHosts 是序列化到tm上的List,也是Elasticsearch6ApiCallBridge这个类(在job包中)的私有属性。这意味着实参 httpHosts的类 优先由 ChildFirstClassLoader加载,且基于事实1,ChildFirstClassLoader能加载到HttpHost。

RestClient类位于elasticsearch-rest-client,即在flink/lib目录,由于我们打包的时候不会将elasticsearch-rest-client打进来,所以ChildFirstClassLoader无法加载到这个类,只能由AppClassLoader加载,而且由于事实2,AppClassLoader也能加载到HttpHost。

这么一来,就会出现上面报错!

解决方案:

最初我们通过将flink改为parent-first,能解决。经过分析:这是因为ParentFirstClassLoader不会先从job包中加载HttpHost,转而由AppClassLoader加载HttpHost,这样就不会有冲突。

从上述根因分析,还有一个方案是将elasticsearch-rest-client等相关jar也打包到job里面,这样保证全部由ChildFirstClassLoader加载。不过这样引入private jar,造成了版本管理的混乱。

flink支持classloader.parent-first-patterns.additional,在child-first的前提下,对某些类做parent-first,实测配置有效,但由于类加载连带关系复杂,无法穷举,所以作罢。

最后

以上就是故意薯片为你收集整理的擎创技术流 | java多类加载器类冲突案例分析起因报错错误描述的意思是:分析原因:事发代码:分析:解决方案:的全部内容,希望文章能够帮你解决擎创技术流 | java多类加载器类冲突案例分析起因报错错误描述的意思是:分析原因:事发代码:分析:解决方案:所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部