0
点赞
收藏
分享

微信扫一扫

JAVA系列:双亲委托模型

Mezereon 2022-03-12 阅读 62



双亲委托模型

JAVA系列:双亲委托模型_字节码

工作过程可以分为两步:



  • 首先从底向上的检查类是否已经加载过,就是这行代码:​​Class<?> c = findLoadedClass(name);​
  • 如果都没有加载过的话,那么就自顶向下的尝试加载该类。




demo

public class MyClassLoader extends ClassLoader {
//指定路径
private String path ;


public MyClassLoader(String classPath){
path=classPath;
}

/**
* 重写findClass方法
* @param name 是我们这个类的全路径
* @return
* @throws ClassNotFoundException
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class log = null;
// 获取该class文件字节码数组
byte[] classData = getData();

if (classData != null) {
// 将class的字节码数组转换成Class类的实例
log = defineClass(name, classData, 0, classData.length);
}
return log;
}

/**
* 将class文件转化为字节码数组
* @return
*/
private byte[] getData() {

File file = new File(path);
if (file.exists()){
FileInputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(file);
out = new ByteArrayOutputStream();

byte[] buffer = new byte[1024];
int size = 0;
while ((size = in.read(buffer)) != -1) {
out.write(buffer, 0, size);
}

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {

e.printStackTrace();
}
}
return out.toByteArray();
}else{
return null;
}


}
}


源码分析

JAVA系列:双亲委托模型_java_02

this.getClass().getClassLoader().loadClass("com.xxx.Test.class") ;

JAVA系列:双亲委托模型_java_03

findLoadedClass 此方法负责从当前ClassLoader实例对象的缓存中寻找已加载的类,调用的为native方法。



findClass 此方法直接抛出ClassNotFoundException异常,因此要通过覆盖loadClass或此方法来以自定义的方式加载相应的类。

JAVA系列:双亲委托模型_java_04

findSystemClass  此方法是从sun.misc.Launcher$AppClassLoader中寻找类,如果未找到,则继续从BootstrapClassLoader中寻找,如果仍然未找到,返回null

JAVA系列:双亲委托模型_字节码_05

defineClass 此方法负责将二进制字节流转换为Class对象,这个方法对于自定义类加载器而言非常重要。如果二进制的字节码的格式不符合jvm class文件格式规范,则抛出ClassFormatError异常;如果生成的类名和二进制字节码不同,则抛出NoClassDefFoundError;如果加载的class是受保护的、采用不同签名的,或者类名是以java.开头的,则抛出SecurityException异常。


JAVA系列:双亲委托模型_加载_06

JAVA系列:双亲委托模型_加载_07

resolveClass 此方法负责完成Class对象的链接,如果链接过,则直接返回。

JAVA系列:双亲委托模型_字节码_08



双亲委派模型的好处:


(1)主要是为了安全性,避免用户自己编写的类动态替换 Java的一些核心类,比如 String。

(2)同时也避免了类的重复加载,因为 JVM中区分不同类,不仅仅是根据类名,相同的 class文件被不同的 ClassLoader加载就是不同的两个类。



常见异常


ClassNotFoundException: 这是最常见的异常,产生这个异常的原因为在当前的ClassLoader 中加载类时,未找到类文件,

NoClassDefFoundError:这个异常是因为加载到的类中引用到的另外类不存在,例如要加载A,而A中盗用了B,B不存在或当前的ClassLoader无法加载B,就会抛出这个异常(比如jar包冲突,引入了低版本的jar)。

LinkageError:该异常在自定义ClassLoader的情况下更容易出现,主要原因是此类已经在ClassLoader加载过了,重复的加载会造成该异常(比如jar冲突导致)。



能不能自己写个类叫java.lang.System? 不能。

为了不让我们写System类,类加载采用委托机制,这样可以保证爸爸们优先,爸爸们能找到的类,儿子就没有机会加载。而System类是Bootstrap加载器加载的,就算自己重写,也总是使用Java系统提供的System,自己写的System类根本没有机会得到加载。



如何打破 ClassLoader 双亲委托?


重写 loadClass() 方法。





举报

相关推荐

0 条评论