在最近的项目中,我们遇到了一个典型的库冲突问题 。 我们可以控制的一个组件需要特定版本的Apache Commons库,而另一个组件则需要一个不同的版本。 由于外部限制, 我们无法在Container级别指定任何类加载隔离 。 这不是我们的选择。 相反,我们决定要做的是同时使用两个不同的类定义。 为此,我们必须让当前线程类加载器加载一个类,并手动加载第二个 ; 这样,这两个类仍具有相同的完全限定名称。

这种方法的唯一限制是,我们只能通过反射与手动加载的类进行交互,因为当前上下文使用的是不同的类加载器,
具有不同的类定义,我们可以将加载有类加载器的类的实例强制转换或分配给在另一个上下文中定义的变量。 实际上,我们的实现是Classloader本身:

DirectoryBasedParentLastURLClassLoader extends ClassLoader

这个Classloader的特点是我们给它传递了一个文件系统文件夹路径

public DirectoryBasedParentLastURLClassLoader(String jarDir)

我们的实现扫描文件系统路径以生成URL,并使用此信息将它们传递给我们用CustomClassloader封装的URLClassLoader的包装实例

public DirectoryBasedParentLastURLClassLoader(String jarDir) {super(Thread.currentThread().getContextClassLoader());// search for JAR files in the given directoryFileFilter jarFilter = new FileFilter() {public boolean accept(File pathname) {return pathname.getName().endsWith('.jar');}};// create URL for each JAR file foundFile[] jarFiles = new File(jarDir).listFiles(jarFilter);URL[] urls;if (null != jarFiles) {urls = new URL[jarFiles.length];for (int i = 0; i < jarFiles.length; i++) {try {urls[i] = jarFiles[i].toURI().toURL();} catch (MalformedURLException e) {throw new RuntimeException('Could not get URL for JAR file: ' + jarFiles[i], e);}}} else {// no JAR files foundurls = new URL[0];}childClassLoader = new ChildURLClassLoader(urls, this.getParent());
}

通过此设置,我们可以覆盖主要类加载功能的行为,仅当能够找到请求的类时,才优先考虑从文件夹中进行加载并回落到父类加载器

@Override
protected synchronized ClassloadClass(String name, boolean resolve)throws ClassNotFoundException {try {// first try to find a class inside the child classloaderreturn childClassLoader.findClass(name);} catch (ClassNotFoundException e) {// didn't find it, try the parentreturn super.loadClass(name, resolve);}
}

有了我们的CustomClassloader之后,我们可以通过以下方式使用它:

//instantiate our custom classloader
DirectoryBasedParentLastURLClassLoader classLoader = new DirectoryBasedParentLastURLClassLoader(ClassLoaderTest.JARS_DIR    );
//manually load a specific class
ClassclassManuallyLoaded = classLoader.loadClass('paolo.test.custom_classloader.support.MyBean');
//request a class via reflection
Object myBeanInstanceFromReflection = classManuallyLoaded.newInstance();
//keep using the class via reflection
Method methodToString = classManuallyLoaded.getMethod('toString');
assertEquals('v1', methodToString.invoke(myBeanInstanceFromReflection));

这篇文章的想法及其部分代码来自有关Stackoverflow的有趣讨论。 GitHub上提供了一个可以正常运行的Maven项目,并进行了大量的单元测试以验证正确的行为。

参考: Java –我们的JCG合作伙伴 Paolo Antinori的Handmade Classloader Isolation在Someday Never Comes博客上发表。

翻译自: https://www.javacodegeeks.com/2013/03/java-handmade-classloader-isolation.html

Java –手工Classloader隔离相关推荐

  1. java classloader_Java Classloader原理分析

    类的加载过程指通过一个类的全限定名来获取描述此类的二进制字节流,并将其转化为方法区的数据结构,进而生成一个java.lang.Class对象作为方法区这个类各种数据访问的入口.这个过程通过Java中的 ...

  2. Java Agent的隔离实现以及卸载时一些坑

    转载自   Java Agent的隔离实现以及卸载时一些坑 在<一文带你了解Java Agent>中,让大家了解了Java Agent的来龙去脉,当通过attach方式去动态加载一个Jav ...

  3. Java的ClassLoader加载是怎么保证安全的?

    点击上方蓝色字体,选择"标星公众号" 优质文章,第一时间送达 1.类加载机制 Java中的源码.java后缀文件会在运行前被编译成.class后缀文件,文件内的字节码的本质就是一个 ...

  4. Java基础—ClassLoader的理解

    ##默认的三个类加载器 Java默认是有三个ClassLoader,按层次关系从上到下依次是:- Bootstrap ClassLoader- Ext ClassLoader- System Clas ...

  5. 我的Java开发学习之旅------JAVA 笔记ClassLoader.getResourceAsStream() 与 Class.getResourceAsStream()的区别...

    今天,一读者在我的 Android通过调用Webservice实现手机号码归属地查询 文章中给我回复了一个问题,由于没有具体说明我的sop12.xml文件是放在src目录下,不是和具体操作类Addre ...

  6. android classloader的功能和工作模式,Android中ClassLoader和java中ClassLoader有什么关系和不同...

    一.Java中的ClassLoader是什么? 当写好一个Java应用程序,程序都是由若干个.class类文件组织而成的,当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能,而这些功能都 ...

  7. Java中classLoader浅析

    转载自  Java中classLoader浅析 本文为在公司内部TD上写的一篇小文, 主要讲解java中classLoader基础知识, 现在拿来这里分享一下. 一.问题 请在Eclipse中新建如下 ...

  8. 深度分析Java的ClassLoader机制(源码级别)

    转载自 深度分析Java的ClassLoader机制(源码级别) Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取 ...

  9. java遍历文件和归类_java读取文件的两种方法:java.io和java.lang.ClassLoader

    java读取文件的两种方法:java.io和java.lang.ClassLoader 什么时候使用java.io,什么时候使用java.lang.ClassLoader呢? (注:要是之前读xml文 ...

最新文章

  1. Go 学习笔记(13)— 指针定义、指针特点、空指针、指针数组、指向指针的指针、指针作为函数入参
  2. 架构设计 | 基于Seata中间件,微服务模式下事务管理
  3. Tesseract处理背景渐变的图片
  4. 深度学习一(PyTorch物体检测实战)
  5. [Android 4.4.3] 泛泰A860 Omni4.4.3 20140610 RC2.0 三版通刷 by syhost
  6. windows下强制删除文件
  7. RED GIANT-2023版本更新内容介绍
  8. M-Arch(12)第十一个示例:如何用无源蜂鸣器播放音乐
  9. 关键词搜索淘宝商品列表接口,关键词搜索接口,淘宝关键词搜索接口,item_search - 按关键字搜索淘宝商品列表接口,接口参数说明。
  10. RIGHT-BICEP测试第二次程序
  11. java学习总结(16.06.07)类的静态成员和非静态成员
  12. 数据预处理-Excel 两列合并为一列中间加空格
  13. 悲剧!Google华裔“网红”炫耀公司福利,突然被裁了!
  14. ExifTool 抽取、修改Image tag 信息
  15. centos 6.9界面中文显示英文或者英文界面改中文
  16. 年终总结——过去已逝,未来可期不可欺
  17. 微信小程序开发必备 hellow word
  18. 计算机一级excel操作题百分比,计算机一级excel操作练习题
  19. 温度表达转化(华氏温度到摄氏温度)
  20. 模拟灯光JAVA_著名CG灯光大师谈灯光技术

热门文章

  1. sql server 2008安装_性能不够?基于时序数据库的Zabbix 5.2安装指南
  2. 有序数组中查找第一个比target大的数
  3. fork/join和线程池_从fork-join /线程池调用的Singelton bean中的访问spring请求范围缓存...
  4. 骆驼(camel)命名法_Apache Camel 3 –骆驼核心vs骆驼核心引擎(较小的核心)
  5. s71200模拟量输入输出_模拟用户输入并检查输出的简单方法
  6. mockito java_Java:使用Mockito模拟ResultSet
  7. java迭代器删除两个_两个迭代器的故事
  8. spark 流式计算_流式传输大数据:Storm,Spark和Samza
  9. Java:以CSV格式流式传输JDBC结果集
  10. Java:使用Toxiproxy模拟各种连接问题