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#的无边框窗体阴影绘制方案 - 开源研究系列文章
今天介绍无边框窗体阴影绘制的内容. 上次有介绍使用双窗体的方法来显示阴影,这次介绍使用API函数来进行绘制.这里使用的是Windows API函数,操作系统的窗体也是用的这个来进行的绘制. 1. 项目 ...
- iOS越狱后必装软件
iOS越狱后就跟ubuntu没两样了,很多ubuntu下常用的软件都要装一下 openssh 这个软件可以让我们能够登录iphone Apt-get 用这个软件可以安装很多软件,主要是一些工具调试类软 ...
- 【译】IntelliJ IDEA 2023.2 最新变化——JetBrains IDE 中的 AI 助手
前言 本周所有基于 IntelliJ 的 IDE 和 .NET 工具的 EAP 版本都包含一个主要新功能:AI Assistant.本博文重点介绍我们基于 IntelliJ 的 IDE,并且即将推出专 ...
- 使用GPU搭建支持玛雅(Maya)和Adobe AI,DW,PS的职校云计算机房
背景 学校为职业学校,计算机教室需要进行Maya.Adobe Illustrator.Adobe Dreamweaver.Adobe PhotoShop等软件的教学.每个教室为35用户.资源需求为4核 ...
- 再谈http请求调用(Post与Get),项目研发的核心一环
支持.Net Core(2.0及以上)与.Net Framework(4.0及以上) [目录] 前言 Post请求 Get请求 与其它工具的比较 1[前言] http请求调用是开发中经常会用到的功能. ...
- 使用 Helm 管理应用的一些 Tips
背景 Helm 是一个 Kubernetes 的包管理工具,有点类似于 Mac 上的 brew,Python 中的 PIP:可以很方便的帮我们直接在 kubernetes 中安装某个应用. 比如我们可 ...
- [CISCN 2019华东南]Web11
看到下面connection 里面的内容有一点像抓包出来的 就抓包试试 似乎感觉也没有什么用 看到这个东西,那么就想到改IP 添加X-Forwarded-For:127.0.0.1 发现这个IP随着我 ...
- CF1364B
题目简化和分析: 这题没啥好说的,找其绝对值最大,也就是找到每一个山峰山谷. 这样不仅满足选择的个数最少,并且值最大. 正确性证明: 若 \(a\le b\le c\) \(|a-b|+|b-c|=( ...
- [学习笔记]TypeScript查缺补漏(一):类
@ 目录 基础知识 创建类型 类的初始化 类型和值 JSDoc 注释 字段 私有字段 可选和非可选字段 字段类型约束 Getter/Setter 静态成员 函数重载 构造函数 参数属性 类的实例化 箭 ...
- java_3.运算符、if条件结构
运算符.if条件结构 关系运算符 == != < > >= <= 1.关系运算符运算的结果是boolean类型 2.可以使用boolean类型的变量接收关系运算的结果 publ ...