浅谈一下Java的双亲委派模式
作者:索码理 时间:2021-11-12 02:48:17
说起双亲委派模型,不得不说一下类加载器。
类加载器是什么?
当我们编译Java类时,JVM会创建与平台和机器无关的字节码。字节码存储在.class
文件中。当我们尝试使用一个类时,类加载器就会把它加载到内存中,然后把字节码文件转成Class对象。通俗的说类加载器就是将.class
文件转成Class对象的。
类加载器分类
启动类加载器(Bootstrap Class Loader):负责加载存放在 <JAVA_HOME>\lib
目录下的类,或者被-Xbootclasspath
参数所指定的路径中存放的类。比如:rt.jar
、java.lang.*
包下的类。
扩展类加载器(Extension Class Loader):负责加载<JAVA_HOME>\lib\ext
目录中,或者被java.ext.dirs
系统变量所指定的路径中所有的类库。
应用程序类加载器(Application Class Loader):负责加载用户类路径上所有的类库。
双亲委派模型工作流程
当类加载器收到加载类的请求时,它首先会把请求委派给父加载器去完成,每一层都如此,直到把请求委派给最顶层的启动类加载器,只有当父加载器无法加载委派过来的类时,子加载器才会加载。
JVM在加载⼀个类时,会调⽤AppClassLoader的loadClass
⽅法来加载这个类,不过在这个⽅法中,会先使⽤ExtClassLoader的loadClass
⽅法来加载类,同样ExtClassLoader的loadClass
⽅法中会先使⽤BootstrapClassLoader来加载类,如果BootstrapClassLoader加载到了就直接成功,如果 BootstrapClassLoader没有加载到,那么ExtClassLoader就会⾃⼰尝试加载该类,如果没有加载到,那么则会由AppClassLoader来加载这个类。
所以,双亲委派指得是,JVM在加载类时,会委派给ExtClassLoader和BootstrapClassLoader进⾏加载,如果没加载到才由⾃⼰进⾏加载。
这里说的双亲并不是说类加载器之间是以继承方式实现的,而是以组合的方式实现的,通过源码可以证实这点:
java.lang.ClassLoader#loadClass
private final ClassLoader parent;
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
同时,通过源码我们也可以看到类加载器的加载流程是跟我们描述的一样的:先检查请求加载的类型是否已经被加载过,若没有则调用父加载器的loadClass()
方法,若父加载器为空则默认使用启动类加载器作为父加载器。假如父类加载器加载失败,抛出ClassNotFoundException
异常的话,才调用自己的findClass()
方法尝试进行加载。
双亲委派模型好处
保证唯一性,避免重复加载:类的加载随着它的类加载器一起具备了层级关系,通过这种层级关系避免了重复加载,父类加载器加载了该类,子加载器就无需加载了。
避免核心类被篡改:核心类由启动类加载器加载,即使用户自定义同名核心类也不会被加载。
来源:https://blog.csdn.net/qq_39654841/article/details/128487337
![](/images/zang.png)
![](/images/jiucuo.png)
猜你喜欢
Mybatis generator自动生成代码插件实例解析
![](https://img.aspxhome.com/file/2023/4/65754_0s.png)
Java concurrency之共享锁和ReentrantReadWriteLock_动力节点Java学院整理
![](https://img.aspxhome.com/file/2023/0/84210_0s.png)
C/C++与Java各数据类型所占字节数的详细比较
Java如果通过jdbc操作连接oracle数据库
Java经典面试题最全汇总208道(六)
![](https://img.aspxhome.com/file/2023/4/59064_0s.jpg)
java的Jackson将json字符串转换成泛型List
SpringBoot整合Apollo配置中心快速使用详解
![](https://img.aspxhome.com/file/2023/7/61337_0s.jpg)
Spring MVC中使用Controller如何进行重定向
实例讲解Java的Spring框架中的控制反转和依赖注入
![](https://img.aspxhome.com/file/2023/8/76228_0s.jpg)
java中使用map排序的实例讲解
Android 消息机制问题总结
![](https://img.aspxhome.com/file/2023/5/84715_0s.jpg)
使用JDBC实现数据访问对象层(DAO)代码示例
用Java设计模式中的观察者模式开发微信公众号的例子
![](https://img.aspxhome.com/file/2023/5/88045_0s.jpg)
Java中重载与重写的对比与区别
C#开发WinForm之DataGridView开发详解
![](https://img.aspxhome.com/file/2023/7/83257_0s.png)
浅谈Java中Map和Set之间的关系(及Map.Entry)
![](https://img.aspxhome.com/file/2023/9/57949_0s.jpg)
一种类似JAVA线程池的C++线程池实现方法
![](https://img.aspxhome.com/file/2023/7/79917_0s.png)
JVM之参数分配(全面讲解)
![](https://img.aspxhome.com/file/2023/8/83448_0s.png)
MyBatis特殊字符转义拦截器问题针对(_、\\、%)
![](https://img.aspxhome.com/file/2023/1/78981_0s.png)