千家信息网

什么是类加载器和双亲委派机制

发表于:2025-11-14 作者:千家信息网编辑
千家信息网最后更新 2025年11月14日,本篇内容介绍了"什么是类加载器和双亲委派机制"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!(一)概述
千家信息网最后更新 2025年11月14日什么是类加载器和双亲委派机制

本篇内容介绍了"什么是类加载器和双亲委派机制"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

(一)概述

我们都知道Java代码会被编译成class文件,在class文件中描述了该类的各种信息,class类最终需要被加载到虚拟机中才能运行和使用。

虚拟机把Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成虚拟机可以直接使用的Java类型,这就是虚拟机的类加载机制。

(二)类加载的过程

一个类从被加载到卸载出内存,一共包含下面七个阶段:

加载、验证、准备、解析、初始化、使用、卸载 加载的来源有以下部分:

1、本地磁盘

2、网络下载的.class文件

3、war,jar下加载.class文件

4、从专门的数据库中读取.class文件(少见)

5、将java源文件动态编译成class文件,典型的就是动态代理,通过运行时生成class文件

加载的过程是通过类加载器实现的。有关类加载的其他过程我会在下一章中介绍。

(三)类加载器的分类

类加载器分为系统级别和用户级别:

系统级别的类加载器有:

1、启动类加载器(底层使用C++实现)

2、扩展类加载器(底层使用java实现,是ClassLoader的子类)

3、应用程序类加载器(底层使用java实现,是ClassLoader的子类)

用户级别的类加载器我们统一称为自定义类加载器。

3.1 启动类加载器

首先我们来看看启动类加载器加载了哪些类,启动类加载器负责加载sun.boot.class.path:

public static void bootClassLoaderLoadingPath(){    //获取启动列加载器加载的目录    String bootStrapLoadingPath=System.getProperty("sun.boot.class.path");    //把加载的目录转为集合    List bootLoadingPathList= Arrays.asList(bootStrapLoadingPath.split(";"));    for (String bootPath:bootLoadingPathList){        System.out.println("启动类加载器加载的目录:"+bootPath);    }}

通过上面的代码我们可以获取到启动类加载器所加载的类:

3.2 拓展类加载器

扩展类加载器加载负责加载java.ext.dirs,我们同样写一段代码去加载它:

public static void extClassLoaderLoadingPath(){    //获取启动列加载器加载的目录    String bootStrapLoadingPath=System.getProperty("java.ext.dirs");    //把加载的目录转为集合    List bootLoadingPathList= Arrays.asList(bootStrapLoadingPath.split(";"));    for (String bootPath:bootLoadingPathList){        System.out.println("拓展类加载器加载的目录:"+bootPath);    }}

可以看到,除了加载了JDK目录下的ext外,还加载了Sun目录下的ext

3.3 应用程序类加载器

最后是应用类加载器,它负责加载java.class.path:

public static void appClassLoaderLoadingPath(){    //获取启动列加载器加载的目录    String bootStrapLoadingPath=System.getProperty("java.class.path");    //把加载的目录转为集合    List bootLoadingPathList= Arrays.asList(bootStrapLoadingPath.split(";"));    for (String bootPath:bootLoadingPathList){        System.out.println("应用程序类加载器加载的目录:"+bootPath);    }}

它负责加载工程目录下classpath下的class以及jar包。

(四)双亲委派模型

所谓双亲委派模型,就是指一个类接收到类加载请求后,会把这个请求依次传递给父类加载器(如果还有的话),如果顶层的父类加载器可以加载,就成功返回,如果无法加载,再依次给子加载器去加载。 我们先通过代码来看一下类加载器的层级结构:

public class ClassLoaderPath {    public static void main(String[] args) {        System.out.println(ClassLoaderPath.class.getClassLoader());        System.out.println(ClassLoaderPath.class.getClassLoader().getParent());        System.out.println(ClassLoaderPath.class.getClassLoader().getParent().getParent());    }}

编写一个类,依次输出这个类的类加载器,父类加载器,父类的父类加载器

可以看到首先是应用程序类加载器,它的父类是扩展类加载器,扩展类加载器的父类输出了一个null,这个null会去调用启动类加载器。如果你不信,我们看源码:ClassLoader类

接着从父类加载器往下调用findClass,如果可以加载,就直接返回class,如果不能加载,就依次向下。如果到了自定义加载器还是无法被加载,就会抛出ClassNotFound异常。

我画了一个流程图来展示双亲委派模型的全过程:

双亲委派模型保证了Java程序的稳定运行,可以避免类的重复加载,也保证了 Java 的核心 API 不被篡改。

(五)破坏双亲委派

双亲委派模型并不是绝对的,spi机制就可以打破双亲委派模型。

首先我们需要了解什么是spi,spi(Service Provider Interface)是一种服务发现机制,Java在核心库中定义了许多接口,并且针对这些接口给出调用逻辑,但是并未给出具体的实现。开发者要做的就是定制一个实现类,在 META-INF/services 中注册实现类信息,以供核心类库使用。最典型的就是JDBC。

Java提供了一个Driver接口用于驱动各个厂商的数据库连接,Driver类位于JAVA_HOME中jre/lib/rt.jar中,应该由Bootstrap类加载器进行加载。根据类加载机制,当被加载的类引用了另外一个类的时候,虚拟机就会使用加载该类的类加载器加载被引用的类,因此如果其他数据库厂商定制了Driver的实现类之后,按理说也得把这个实现类放到启动类加载器加载的目录下,这显然是很不合理的。

于是Java提供了spi机制,即使Driver由启动类加载器去加载,但是他可以让线程上下文加载器(Thread Context ClassLoader)去请求子类加载器去完成加载,默认是应用程序类加载器。但是这确实破坏了类加载机制。

"什么是类加载器和双亲委派机制"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

目录 双亲 委派 机制 文件 模型 程序 应用 就是 应用程序 代码 数据 级别 过程 子类 底层 接口 数据库 核心 输出 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 山东交友软件开发哪家可靠 上海进口网络技术诚信为本 cc开发数据库 数据库中数据表怎么隐藏 统计流量 服务器 网络安全需求加速释放 办公电脑如何访问公司服务器 中央电信网络安全和信息化 软件开发团队发展规划 服务器安全防病毒软件 数据库接口连接别的数据库 查找关于网络安全简单的手抄报 我的世界进不去服务器无效会话 碧空之个服务器排队严重 本溪千秋网络技术有限公司 企业该如何选择服务器托管的尺寸 软件开发标书文件评分标准 网络安全法热议 推荐数据库开发工具 qt数据库开发 web服务器只读文件权限 哪种品牌的网络安全零信任 学了一年软件开发能去芯片厂吗 华为云数据库首席架构师 这是哪个国家的服务器翻译 网络安全等级测评多久测评 安徽企业软件开发单价 神武新区服务器开放物品 网易单方块服务器最近推荐 服务器如何圈地
0