Java自定义ClassLoader实现插件类隔离加载 - 原理篇
书接上回
在 Java自定义ClassLoader实现插件类隔离加载文章中,我们通过
自定义ClassLoader + 插件独立打包引入的方式,实现了同依赖不同版本的隔离加载
这次咱们来分析下具体实现原理
打破双亲委派机制
首先,双亲委派机制不会自己去尝试加载类,而是把请求委托给父加载器去完成,依次向上
其次,思考一个问题
以前使用Tomcat部署项目时,webapp目录下可能部署多个项目的war包
这些war包中可能包含同一个类,类全限定名一样,但是实现不一样
那么Tomcat如何保证他们不会冲突呢?
Tomcat正是使用了打破双亲委派机制,给每一个应用创建独立的类加载器实例WebAppClassLoader,并重写loadClass核心方法,使得优先加载当前应用目录下的类
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();
// 查找Class资源
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的源码
第一行用synchronized关键字做了对象锁处理,这里说点额外话题,为啥对象锁用的getClassLoadingLock(name),而不是直接用name作为对象锁,推荐一篇博文讲的非常详细:https://www.cnblogs.com/thisiswhy/p/15892044.html
进入锁以后,通过findLoadedClass方法,先找已经加载过的Class
已经加载过的Class中找不到的话,再通过parent.loadClass(name, false)委托父加载器加载
这段逻辑就是双亲委派的处理
类加载规则
如果一个类由类加载器A加载,那么这个类的依赖类也是由「相同的类加载器」加载。
protected Class<?> findClass(final String name)
throws ClassNotFoundException
{
final Class<?> result;
try {
// AccessController提供了一个默认的安全策略执行机制,它使用栈检查来决定潜在不安全的操作是否被允许
// doPrivileged方法用来终端没有权限不被允许的操作
result = AccessController.doPrivileged(
new PrivilegedExceptionAction<Class<?>>() {
public Class<?> run() throws ClassNotFoundException {
// 获取Class路径
String path = name.replace('.', '/').concat(".class");
// 加载Class资源
Resource res = ucp.getResource(path, false);
if (res != null) {
try {
// 加载Class资源,定义Class类
return defineClass(name, res);
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
} else {
return null;
}
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
}
if (result == null) {
throw new ClassNotFoundException(name);
}
return result;
}
总结
我们通过自定义ClassLoader,清空了父加载器,使得打破了双亲委派机制,不会通过缓存加载到AppClassLoader中已加载过的类
加载的Class类中,其它的依赖类,也是经过我们自定义的ClassLoader进行的加载
因此,我们加载不同的插件包时,可以实现类的隔离加载
Java自定义ClassLoader实现插件类隔离加载 - 原理篇的更多相关文章
- Java虚拟机JVM学习02 类的加载概述
Java虚拟机JVM学习02 类的加载概述 类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对 ...
- java 27 - 1 反射之 类的加载器
说到反射,首先说类的加载器. 类的加载: 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. 加载: 就是指将class文件读入内存,并为之 ...
- Java温故而知新(10)类的加载机制
类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比如热部署等,提高程序的灵活性 ...
- 透过现象看本质:Java类动态加载和热替换
摘要:本文主要介绍类加载器.自定义类加载器及类的加载和卸载等内容,并举例介绍了Java类的热替换. 最近,遇到了两个和Java类的加载和卸载相关的问题: 1) 是一道关于Java的判断题:一个类被首次 ...
- java类的加载机制
什么是类装载器ClassLoader ClassLoader是一个抽象类 ClassLoader的实例将读入Java字节码将类装载到JVM中 ClassLoader可以定制,满足不同的字节码流获取方式 ...
- java类的加载、链接、初始化
JVM和类的关系 当我们调用JAVA命令运行某个java程序时,该命令将会启动一条java虚拟机进程,不管该java程序有多么复杂,该程序启动了多少个线程,它们都处于该java虚拟机进程里.正如前面介 ...
- java 类的加载、连接和初始化
JVM和类 调用Java命令运行Java程序时,该命令将会启动一条Java虚拟机进程,不管该Java程序启动了多少条线程,创建了多少个变量,它们都处于该Java虚拟机进程里,共享该JVM进程的内存区. ...
- Java类的加载的一个小问题
前言 之前写了一篇文章专门介绍了一下类的加载和对象的创建流程,然后收到了一个博友的疑问,觉得蛮好的,在这里和大家分享下. 博文地址:[Java基础]Java类的加载和对象创建流程的分析 疑问 类在加载 ...
- <JVM中篇:字节码与类的加载篇>04-再谈类的加载器
笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...
- 别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】
目录 1.什么是类的加载(类初始化) 2.类的生命周期 3.接口的加载过程 4.解开开篇的面试题 5.理解首次主动使用 6.类加载器 7.关于命名空间 8.JVM类加载机制 9.双亲委派模型 10.C ...
随机推荐
- C# OpenCVSharp图像入门_给绿幕图片视频加背景
OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库.OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研 ...
- Redis专题-秒杀
Redis专题-并发/秒杀 开局一张图,内容全靠"编". 昨天晚上在群友里看到有人在讨论库存并发的问题,看到这里我就决定写一篇关于redis秒杀的文章. 1.理论部分 我们看看一般 ...
- 实现在Qt窗口中嵌套SDL
实现在Qt窗口中嵌套SDL 在现代软件开发中,多媒体处理和交互性成为应用程序不可或缺的一部分.Qt作为一个强大的GUI框架,为开发者提供了丰富的图形.界面和事件处理工具.然而,有时候,我们可能需要更多 ...
- Netty源码学习3——Channel ,ChannelHandler,ChannelPipeline
系列文章目录和关于我 零丶引入 在Netty源码学习2--NioEventLoop的执行中,我们学习了NioEventLoop是如何进行事件循环以及如何修复NIO 空轮询的bug的,但是没有深入了解I ...
- 循环神经网络RNN完全解析:从基础理论到PyTorch实战
在本文中,我们深入探讨了循环神经网络(RNN)及其高级变体,包括长短时记忆网络(LSTM).门控循环单元(GRU)和双向循环神经网络(Bi-RNN).文章详细介绍了RNN的基本概念.工作原理和应用场景 ...
- shell、python时间函数小结
有时需要写一些定时任务脚本,简单总结一下,备忘. 1. 获取当前时间 python 在windows下精确到0.001秒,linux下时间精度为0.000001秒 >>> impor ...
- 「atcoder - agc054c」Roughly Sorted
link. 高妙题,我只会到构造下界那一步-- 构造下界比较容易,只需要注意到交换一次最多让序列向合法迫近一步即可.则答案下界为 \(\sum_i \max\{\left(\sum_{j < i ...
- Solution -「LOCAL 28731」「重庆市 2021 中学友谊赛」Rainyrabbit 爱求和
Description Link. \(\operatorname{Rainyrabbit}\) 是一个数学极好的萌妹子,近期他发现了一个可爱的函数: \[f(n,m,k)=\sum_{d=1}^n ...
- ORA-01008:并非所有变量都已绑定-解决办法
近期批量处理数据,后台用JAVA编写,连接Oracle数据库,程序运行报ORA-01008问题.解决这个问题时遇见的坑较多,下面复盘现象.问题提出解决办法,希望能帮到遇见同类问题的你. 调试问题: 后 ...
- Python并发编程——IO模型、阻塞IO、非阻塞IO、多路复用、异步IO、IO模型比较、selectors模块、复习网络和并发知识点
文章目录 每日测验 一 IO模型介绍 二 阻塞IO(blocking IO) 三 非阻塞IO(non-blocking IO) 四 多路复用IO(IO multiplexing) 五 异步IO(Asy ...