如何快速写一个违背双亲委托机制的classloader
很多情况下,不得以必须写个classloader来满足需求。例如你一个工程里你想用相同的数据库的多个版本,自己制定了一个jar包目录,没有classloader管理等等。如果是一个遵循java已经规定好的机制的classloader(双亲委托以及加载依赖类的classloader继续加载剩下的类)。直接继承classloader就可以。(一般选择urlclassloder,他帮你实现了不少功能)。但是往往有需求需要加载两个相同的Jar包,例如web应用中的webappclassloader。不同的应用的相同war包都需要被同级的加载,优先级高于was的lib目录。
编写classloader
加入缓存
classloader的本质是加载字节码到内存,而且相同字节码不能被重复加载,所以我们需要加入缓存,简单选择一个hashmap就可以
Map> classMap =new HashMap>();
覆写关键方法 不论你是class.forname,还是loadclass方法的调用,最后都是要调用loadClass的,所以这里一定要重写这个方法,这里就要加入破坏双亲委托机制的逻辑。
public Class> loadClass(String name) throws ClassNotFoundException {
Class> classLoaded = classMap.get(name);
if (classLoaded != null) {
return classLoaded;
}
Class> findClass = null;
try {
findClass = findClass(name);
} catch (Exception e) {
//还可以从父类查找,这个异常吞掉,如果没有父类会抛出
}
if (findClass != null) {
classMap.put(name, findClass);
return findClass;
}
return super.loadClass(name);
}
逻辑很简单,先从缓存找是否已经加载了class,对已经加载的就直接返回,防止重复加载。此处调用了findClass方法,findClass是可以覆写的,这里为了简洁的实现,就不再覆写了。
拿这样的classloader如果有重复的jar包可能是有问题的。问题就在他的findclass中。findClass找到资源后会通过defineClass(String name, Resource res)来加载类,这里最后会调用getPackage来获取包。下面是找的流程。
protected Package getPackage(String name) {
Package pkg;
synchronized (packages) {
pkg = packages.get(name);
}
if (pkg == null) {
if (parent != null) {
pkg = parent.getPackage(name);
} else {
pkg = Package.getSystemPackage(name);
}
if (pkg != null) {
synchronized (packages) {
Package pkg2 = packages.get(name);
if (pkg2 == null) {
packages.put(name, pkg);
} else {
pkg = pkg2;
}
}
}
}
return pkg;
}
这里很明显的,先从已经加载的包中查找,如果没有就先从父classloader找,最后又进行了双亲委托机制。所以这个地方也需要覆写。
protected Package getPackage(String name) {
return null;
}
比较暴力直接返回空。在后面的判断中,如果此处返回null,后续就会重新新建一个对象,然后放入一个缓存结构,还是一个hashmap
private final HashMap packages = new HashMap<>();
为空的结果只是更新一下缓存。这里没有对类加载产生问题。
最终结果
public class MyClassloader extends URLClassLoader {
public MyClassloader(URL[] urls) {
super(urls);
}Map> classMap = new HashMap>();
@Override
public Class> loadClass(String name) throws ClassNotFoundException {
Class> classLoaded = classMap.get(name);
if (classLoaded != null) {
return classLoaded;
}
Class> findClass = null;
try {
findClass = findClass(name);
} catch (Exception e) {
//还可以从父类查找,这个异常吞掉,如果没有父类会抛出
}
if (findClass != null) {
classMap.put(name, findClass);
return findClass;
}
return super.loadClass(name);
}@Override
protected Package getPackage(String name) {
return null;
}
}
【如何快速写一个违背双亲委托机制的classloader】只要覆写两个方法就好。这样就能比较小的改造成一个破坏双亲委托机制的classloader。
推荐阅读
- 第三节|第三节 快乐和幸福(12)
- 考研英语阅读终极解决方案——阅读理解如何巧拿高分
- 如何寻找情感问答App的分析切入点
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus使用queryWrapper如何实现复杂查询
- 拉黑家人一整年之后,以为会快乐,最后却抑郁症!!
- 如何在Mac中的文件选择框中打开系统隐藏文件夹
- 漫画初学者如何学习漫画背景的透视画法(这篇教程请收藏好了!)
- java中如何实现重建二叉树
- Linux下面如何查看tomcat已经使用多少线程