问题描述

假设有C1类和C2类都依赖C0,C1和C2分别用不同的2个类加载器加载,而这两个类加载器都能在自己的类加载路径中加载到C0,这个时候如果在C1中调用C2的某个方法(注:这个方法的签名中依赖了C0)就会出现LinkageError错误。

用例模拟及分析

冲突的依赖类,模拟问题描述中的C0

package loader;public class ConflictDependence {
}

发生错误的类,模拟问题描述中的C2

package loader;public class ErrorTester {static {// 在其它ClassLoader中必需使用一次这个 MyDependence 依赖,// 这样在另一个ClassLoader使用的时候就会出错System.out.println("ErrorTester MyDependence Location: " +ConflictDependence.class.getProtectionDomain().getCodeSource());}// 不会出错的方法
//    public static void test0() {//        System.out.println("ErrorTester MyDependence Location: " +
//                ConflictDependence.class.getProtectionDomain().getCodeSource());
//    }// 出错方法
//    public static void test(ConflictDependence a) {//    }// 出错方法public static ConflictDependence test() {return null;}
}

被另一个类加载器加载的类,模拟问题描述中的C1

package loader;public class SubClass {private ConflictDependence myDependence;public SubClass() {System.out.println(ConflictDependence.class.getProtectionDomain().getCodeSource());ConflictDependence test = ErrorTester.test();}
}

测试类

package loader;import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;public class Test {public static void main(String[] args) throws Exception {URL[] urls = new URL[]{new File("/home/conquer/Desktop/jse.jar").toURI().toURL()};SubFirstLoader newLoader = new SubFirstLoader(urls);ErrorTester.test();Class<?> b = newLoader.loadClass("loader.SubClass");b.newInstance();}static class SubFirstLoader extends URLClassLoader {public SubFirstLoader(URL[] urls) {super(urls);}@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {try {// 从自身类路径中加载return this.findClass(name);} catch (Exception e) {// 从父ClassLoader加载return super.loadClass(name);}}}
}

模拟说明:
1.将以上的4个类打jar包,名为为jse.jar或其他名字
2.从jar中删除ErrorTester和Test两个class文件
3.修改测试程序Test中的jar路径,运行测试即可看到出错信息

问题分析:
测试中使用了两个类加载器来加载类,使用系统类加载器加载ErrorTester,这个类依赖了ConflictDependence,可以看到静态块里同时也打印出系统类加载器也从自己的加载路径中加载了ConflictDependence,然后使用自定义的类加载器(一个子优先的类加载器)加载了Sub Class,并通过反射构造其实例,构造过程中依赖了ConflictDependence,所以会去尝试加载ConflictDependence,由于自定义的加载器是子优先模式的,会先从自身类加载路径查找并加载,所以可以加载到一个ConflictDependence,注意这个ConflictDependence和系统类加载器加载的并不是同一个,在SubClass中调用了ErrorTester.test()方法,这个方法的签名依赖的是系统类加载器加载的ConflictDependence,而SubClass也有同名的不同实例的ConflictDependence,因此就产生了冲突,这里表现为LinkageError,就是SubClass将自己加载的ConflictDependence链接到ErrorTester.test()方法(这个方法的签名在当前内存中依赖的是系统类加载器加载的ConflictDependence)时产生错误。
继续测试发现,调用test0()方法并无错误,这是因为test0()方法的签名没有依赖到冲突的
ConflictDependence(这里需要注意方法体内的ConflictDependence并不会产生冲突错误,这是因为方法体的字节码不会编译到SubClass的字节码中,类加载器约束检查只会在当前这个SubClass类的方法中检查冲突,其他方法体的冲突是在其他方法体内检查的,简单说就是类冲突检查的单元是在一个方法体内),
另外需要说明的是方法的参数和方法的返回值都属于方法的签名,方法的签名都会编译到调用端的方法体内,所以上面的void test(ConflictDependence a)方法和ConflictDependence test()都会出错。
另外需要注意的是:ErrorTester中使用了静态块一个是可以看出当前实例加载的是哪个ConflictDependence,另一个原因是为了触发一下让系统类加载加载一下ConflictDependence,以促成后面的冲突问题产生,其实如果不在静态块中触发,在test()的方法体中触发也是可以产生此问题的,同理SubClass中的打印也是为了触发当前类的类加载器加载一下ConflictDependence。

关于更多类加载问题,请参考:
ClassLoader问题剖析

罕见类加载冲突问题:LinkageError相关推荐

  1. 擎创技术流 | java多类加载器类冲突案例分析

    众所周知,jvm类加载机制采用双亲委派机制.但在有些框架中,常常为了提供某种形式的"隔离和沙盒",自定义一种称为ChildFirst的类加载器,简单的说就是破坏了双亲委派,由自定义 ...

  2. java log4j logback jcl_内部分享:如何解决Java日志框架冲突问题。

    来源:https://urlify.cn/E7zEfq # 前言 Java 有很多的日志框架可以选择,当同一个项目中出现多种日志框架时就很容易出现日志框架冲突的问题,导致日志打印不出来.本文将以一次典 ...

  3. 阿里P7/P8学习路线图——技术封神之路

    一.基础篇 JVM JVM内存结构 堆.栈.方法区.直接内存.堆和栈区别 Java内存模型 内存可见性.重排序.顺序一致性.volatile.锁.final 垃圾回收 内存分配策略.垃圾收集器(G1) ...

  4. Javag工程师成神之路(2019正式版)

    主要版本 更新时间 备注 v1.0 2015-08-01 首次发布 v1.1 2018-03-12 增加新技术知识.完善知识体系 v2.0 2019-02-19 结构调整,更适合从入门到精通: 进一步 ...

  5. 摘自《Java工程师成神之路》2018修订版,自我勉励

    一.基础篇JVM JVM内存结构 堆.栈.方法区.直接内存.堆和栈区别 Java内存模型 内存可见性.重排序.顺序一致性.volatile.锁.final 垃圾回收 内存分配策略.垃圾收集器(G1). ...

  6. 你和阿里资深架构师之间,差的不仅仅是年龄(进阶必看)

    导读:阅读本文需要有足够的时间,笔者会由浅到深带你一步一步了解一个资深架构师所要掌握的各类知识点,你也可以按照文章中所列的知识体系对比自身,对自己进行查漏补缺,觉得本文对你有帮助的话,可以点赞关注一下 ...

  7. Java工程师修炼之路

    文章来自于微信公众号:Hollis,作者网站:https://www.hollischuang.com/ 转载过来方便查看 1 基础篇 01 面向对象 → 什么是面向对象 面向对象.面向过程 面向对象 ...

  8. 初级Java开发与架构之间的差距不仅仅是开发时间

    转载自  初级Java开发与架构之间的差距不仅仅是开发时间 一.基础篇 JVM JVM内存结构 堆.栈.方法区.直接内存.堆和栈区别 Java内存模型 内存可见性.重排序.顺序一致性.volatile ...

  9. Java成神之路[转]

    阿里大牛珍藏架构资料,点击链接免费获取 针对本文,博主最近在写<成神之路系列文章> ,分章分节介绍所有知识点.欢迎关注. 主要版本 更新时间 备注 v1.0 2015-08-01 首次发布 ...

最新文章

  1. 敏捷研发之代码评审与工具
  2. 基于linux的驱动设计,《基于LINUX的虚拟驱动设计》-毕业论文.doc
  3. windows十大必禁服务
  4. 【翻译】了解Ext JS 5的小部件
  5. linux cache lru回收,LRU cache 算法
  6. 设计模式--门面(Facade)模式
  7. 房价集体上扬?最新房价数据分析看房价走势
  8. python sklearn 归一化_第3章 Sklearn概述
  9. oracle不能单步调试,oracle bug之vipca无法执行问题的解决
  10. CentOS 7.2 Ubuntu 18部署Rsync + Lsyncd服务实现文件实时同步/备份
  11. 关于页面布局的一些注意点
  12. 2018年AI和ML(NLP、计算机视觉、强化学习)技术总结和2019年趋势(上)
  13. 绝不在构造/析构函数中使用虚函数
  14. AD ---- 活动目录的日常管理操作(3)
  15. PDF内嵌字体分析 - 提取的文字是乱码原因分析
  16. Brocade 光纤交换机配置命令
  17. 论文阅读:Permutation Matters: Anisotropic Convolutional Layer for Learning on Point Clouds
  18. LZX 定义 - 转帖
  19. 服务器硬盘rad技术,服务器硬盘RAD选用.doc
  20. 华为机试 放苹果

热门文章

  1. 企企通携手塑料新材料行业龙头【佛塑科技】,以数字化采购引领行业转型升级
  2. 二叉搜索树(BST)Go实现
  3. 自己不行,别抱大腿!
  4. table表头固定,内容滚动
  5. 部署网站到服务器(Heroku)
  6. 不同网段也可以远程桌面
  7. -webkit-overflow-scrolling: touch兼容问题
  8. 京东搜索权重新规 京东搜索权重衰退模型解读
  9. 还不懂 TCP/IP 是啥?看这一篇就够了!!!
  10. 代码随想录第二十二天