通俗易懂的 JAVA 类加载器
JVM中有两种类型的类加载器,由C++编写的及由Java编写的。除了启动类加载器(Bootstrap Class Loader)是由C++编写的,其他都是由Java编写的。由Java编写的类加载器都继承自类java.lang.ClassLoader。
各种类加载器之间存在着逻辑上的父子关系
启动类加载器BootClassLoader
启动类加载器是由C++编写,启动类加载器核心就是以下逻辑
java.c,入口LoadMainClass
LoadMainClass 主要调用的是checkAndLoadMain,GetLauncherHelperClass作用是找GetLauncherHelperClass类,而checkAndLoadMain就在GetLauncherHelperClass里
checkAndLoadMain主要是加载main函数所在的类,启动扩展类加载器、应用类加载器也是在这个时候完成的
int JNICALL
JavaMain(void * _args)
{
...
mainClass = LoadMainClass(env, mode, what);
...
}
static jclass
LoadMainClass(JNIEnv *env, int mode, char *name)
{
jclass cls = GetLauncherHelperClass(env);
...
NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,
"checkAndLoadMain",
"(ZILjava/lang/String;)Ljava/lang/Class;"));
...
}
jclass
GetLauncherHelperClass(JNIEnv *env)
{
if (helperClass == NULL) {
NULL_CHECK0(helperClass = FindBootStrapClass(env,
"sun/launcher/LauncherHelper"));
}
return helperClass;
}
总结:这套逻辑做的事情就是通过启动类加载器加载sun.launcher.LauncherHelper类,执行该类的方法checkAndLoadMain,最终完成加载main函数所在的类
双亲委派
双亲委派:如果一个类加载器收到了加载某个类的请求,则该类加载器并不会去加载该类,而是把这个请求委派给父类加载器,每一个层次的类加载器都是如此,因此所有的类加载请求最终都会传送到顶端的启动类加载器;只有当父类加载器在其搜索范围内无法找到所需的类,并将该结果反馈给子类加载器,子类加载器会尝试去自己加载。
打破双亲委派
因为在某些情况下父类加载器需要委托子类加载器去加载class文件。受到加载范围的限制,父类加载器无法加载到需要的文件
以jdbc为例,由于jdbc定义在jdk当中的,而其实现由各个数据库的服务商来提供,那么问题就来了,DriverManager(也由jdk提供)要加载各个实现了jdbc接口的实现类,然后进行管理,但是DriverManager由启动类加载器加载,而其实现是由服务商提供的,由应用类加载器加载,这个时候就需要启动类加载器来委托子类来加载实现类,从而破坏了双亲委派。
打破双亲委派的意思其实就是不委派、向下委派
打破双亲委派两种方法
SPI
SPI是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类
SPI机制 向下委派打破双亲委派
自定义类加载器
自定义类加载器例子:
重写classload
伪代码:
// 打破双亲委派
if (name.startsWith("com.XXX")) {
// com.XXX包下的所有类不委派
c = findClass(name);
} else {
// 其他包委派
c = this.getParent().loadClass(name);
}
上一篇: 您不知道的班级装载机问题
下一篇: 什么是类加载器?什么是类加载器?
推荐阅读
-
Java 构造方法(与类同名的方法)、类方法、类变量、实例方法、实例变量
-
Java 的 ID 号工具类
-
深入分析 Java 中的 MyBatis Plus 注释 @InterceptorIgnore:拦截器行为的优雅控制
-
为飞思卡尔系列微控制器开发引导加载程序的初步经验
-
35 岁实现财务*,腾讯程序员手握2300万提前退休?-1000万房产、1000万腾讯股票、加上300万的现金,一共2300万的财产。有网友算了一笔账,假设1000万的房产用于自住,剩下1300万资产按照平均税后20-50万不等进行计算,大约花上26-60年左右的时间才能赚到这笔钱。也就是说,普通人可能奋斗一辈子,才能赚到这笔钱。在很多人还在为中年危机而惶惶不可终日的时候,有的人的35岁,就已经安全着陆,试问哪个打工人不羡慕?但问题是有这样财富积累必然有像样的实力做靠山。没有人可以不劳而获。 看到这里,肯定有人说,那么对于普通人来说,卷可能真就成了唯一的出路。但是卷也有轻松的卷,“偷懒”的卷法,对于程序员而言,刨除掉一时无法改掉的开会传统占用的大部分时间,如何把有限的时间和精力放在真正重要的架构设计、需求设计上,而不是重复的造*,编码、改bug、手动测试。因此在科技改变生活的今天,学会使用AI工具成为程序员们的必备技能。 以全栈式全自动的软件开发工具飞算SoFlu软件机器人为例,作为全球首款面向微服务架构设计和最佳实践的软件机器人,SoFlu软件机器人改变了原来手工编码的作业模式,通过可视化拖拽方式以及参数配置就能实现等同于编写复杂代码的业务逻辑,在设计业务逻辑时就完成了微服务应用开发,做到“业务即图,图即代码”,实现“软件开发,十倍提效”。 而作为飞算SoFlu软件机器人的一个重要组成部分,FuncGPT(慧函数)支持所有类型函数创建。通过自然语言描述Java函数需求,实时生成高质量、高可读性的Java函数代码。生成代码可直接复制到IDEA,或一键导入Java全自动开发工具函数库。 FuncGPT(慧函数)具有五大核心能力: ● 自然语言:通过自然语言即可生成函数,降低软件开发门槛。 ● 秒级函数开发:全自动秒级开发函数,秒级完成,效率千倍提升。 ● 一站式函数开发应用:函数生成即可直接应用,效率、安全有保障。 ● 质量可靠:生成的函数代码符合业界规范、具备良好的可读性,符合最优解。 ● 灵活生成:可以根据开发人员的具体需求生成并支持调整和修改。 以“将文件流转换为File对象”这个需求为例,以下是FuncGPT(慧函数)秒级生成的代码: / 类名:FileConverter // 函数名:convertStreamToFile // 函数功能:将文件流转换为File对象 // POM依赖包:无 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class FileConverter { /** * 将文件流转换为File对象 * @param inputStream 文件流 * @param filePath 文件路径 * @param fileName 文件名 * @return 转换后的File对象 * @throws IOException 如果发生I/O异常 */ public static File convertStreamToFile(InputStream inputStream, String filePath, String fileName) throws IOException { File file = new File(filePath + File.separator + fileName); // 创建File对象 try (FileOutputStream outputStream = new FileOutputStream(file)) { // 创建文件输出流 byte buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { // 从文件流读取数据并写入文件 outputStream.write(buffer, 0, bytesRead); } } return file; // 返回转换后的File对象 } } // 函数示例 // 将文件流转换为File对象示例 // 入参:inputStream,文件流 // 入参:filePath,文件路径 // 入参:fileName,文件名 // 出参:file,转换后的File对象 // 调用示例: // InputStream inputStream = new FileInputStream("example.txt"); // String filePath = "C:\\Users\\User\\Documents"; // String fileName = "example.txt"; // File file = FileConverter.convertStreamToFile(inputStream, filePath, fileName); // System.out.println(file.getAbsolutePath); // 输出结果:例如,将文件流转换为File对象后,文件的绝对路径为:C:\Users\User\Documents\example.txt // 则输出结果为:C:\Users\User\Documents\example.txt 通过分析,不难发现以上代码:
-
Java 面试问题:解释 Java 中的并发工具类 ConcurrentHashMap 如何工作,并列举经典应用示例
-
[PyTorch 与深度学习] 4、PyTorch 的数据集和数据加载器详细使用教程
-
预习 Java 基础知识 - 以通俗易懂的文字不断更新!
-
用通俗易懂的语言理解 Java 设计模式的指南
-
自动重载预加载中的 STM32CubeMX 定时器配置时钟