双亲委派机制

双亲委派机制简单来说就是类加载的一个顺序机制,简单来说就是:当一个类加载器收到加载请求时,检查该类是否已经被当前加载器加载过。如果已加载,直接返回;若未加载,开始委派,先委托父加载器去加载,父加载器加载不了,才自己加载。

首先介绍一下类加载器有哪几个?

1、启动类加载器:负责加载 <JAVA_HOME>/lib 目录下的核心类库(如 rt.jar、resources.jar、sun.boot.class.path 路径下的包

2、扩展类加载器:负责加载 <JAVA_HOME>/lib/ext 目录,或者由 -Djava.ext.dirs 系统变量指定路径下的所有类库。

3、应用程序类加载器:负责加载用户类路径(ClassPath)、-classpath 或 -cp 参数指定的类库

那么为什么需要双亲委派机制呢?

1、为了保证核心类库安全:如果用户自己创建一个Java.lang.String的类放在自己的项目下,那么根据双亲委派机制的加载逻辑,只有最高层级的启动类加载器才能进行加载,这样就保证了核心类的安全性

**2、 避免类重复加载:**从最底层的应用程序类加载器开始检查一直到最上层的类加载器,只要检查到这个类已经被加载了,那么就会直接返回确保了类只加载一次

3、保证类的唯一性: 类身份 = (全限定名, 定义类加载器),同一个类名,最终由同一个定义类加载器加载,得到同一个 Class 对象

那么有些场景为什么要打破双亲委派机制?如何打破双亲委派机制?

1、Tomcat启动多个应用

我们知道Tomcat可以启动多个应用,每个应用可能会出现多个spring依赖的版本,那么不同的spring版本依赖的名称肯定是相同的,那么根据双亲委派机制,就会把相同的名称的依赖包下的类只加载一次,这样就会出现版本不一致的情况

那么如何解决呢?

修改ClassLoader 并重写 loadClass 方法

1、设计每个应用都有独立的应用程序类加载器

2、BootstrapClassLoader 尝试去加载(仅针对 java.* 等核心包做安全隔离)。

WebAppClassLoader 优先尝试去加载(直接去 WEB-INF/classes 和 WEB-INF/lib 找)。

System/CommonClassLoader 最后才尝试去加载(如果本地 WEB-INF 找不

2、JDBC

DriverManager 位于 java.sql 包,由启动类加载器 Bootstrap ClassLoader 加载。DriverManager 需要加载 MySQL 的 com.mysql.cj.jdbc.Driver,这个类在 CLASSPATH 下,Bootstrap 加载不了。

那么如何解决呢?

SPI 与线程上下文类加载器

核心库的加载器无法向下识别第三方驱动,于是引入 Thread.currentThread().getContextClassLoader(),让父加载器逆向请求子加载器去加载驱动实现。上下文类加载器就是应用程序类加载器,这样就能够将驱动类正常加载

总结:

想要打破双亲委派机制有两种方式:

1、自定义ClassLoader 并重写 loadClass 方法

2、改变加载顺序,如:调用上下文类加载器

最后附上一个表格关于是否重写对应的类加载器的方法

方法 职责 是否可重写
loadClass 双亲委派逻辑 可重写,但不推荐
findClass 读取字节流,定义类 推荐重写
defineClass 把字节流变成 Class 对象 final,不可重写
findLoadedClass 检查是否已加载 final
resolveClass 触发链接 final
相关推荐
Shaoshing4 小时前
ThreadLocal
java·jvm·threadlocal
写后端的胖头鱼4 小时前
一文详解CAS
java·jvm·spring·cas·乐观锁·自旋
鱼宵5 小时前
Spring AI 提示词模板:{变量} 参数化 + few-shot,一条提示词反复用
java·人工智能·spring·few-shot·提示词工程·springai
调试人生的显微镜5 小时前
iOS开发入门:Interface Builder、基础控件及UITextField详解
后端·ios
泡海椒5 小时前
巡检照片与工单附件:jquick-pdf 图片嵌入的业务实战
后端
蜗牛互联网5 小时前
Python消费Responses SSE事件:增量文本、超时与取消
java·开发语言·人工智能·后端·python
AI持续学习5 小时前
文档权限变更如何回归测试?账号、空间、文件和分享链接用例清单
后端
wanderist.5 小时前
线性筛法详解:从筛质数到欧拉函数、Möbius 函数与约数函数
java·数据结构·算法
All for pursuit.5 小时前
【设计-1】208.实现Trie (前缀树)
数据结构·c++·算法·leetcode
谢亮_vipxieliang5 小时前
Go Worker Pool 设计——从原理到生产级实现
开发语言·后端·golang