JVM工作原理与实战(十三):打破双亲委派机制-线程上下文类加载器

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了打破双亲委派机制的方法、线程上下文类加载器等内容。

一、打破双亲委派机制的方法

双亲委派机制的核心思想是:当一个类加载器接收到加载类的请求时,它首先不会自己去尝试加载,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器(Bootstrap ClassLoader)中去,只有当父类加载器无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。

当一个类加载器接收到加载类的任务时,会自底向上查找是否加载过再由顶向下进行加载。

image.gif

双亲委派机制是Java类加载器的重要特性,但在某些情况下,可能需要打破这种机制。以下是打破双亲委派机制的方法:

  • 自定义类加载器:在Java中,可以通过继承ClassLoader并重写其loadClass方法来创建自定义类加载器。通过这种方式,可以打破双亲委派机制,实现类的隔离。例如,在Tomcat中,每个Web应用都有自己的类加载器,从而实现了应用之间的类隔离。当两个Web应用中有相同限定名的类时,如Servlet类,Tomcat通过自定义类加载器保证它们是不同的类。
  • 线程上下文类加载器:在Java中,每个线程都有一个关联的上下文类加载器。通过设置线程的上下文类加载器,可以实现类的加载。例如,JDBC和JNDI等就是利用线程上下文类加载器来加载类的。
  • Osgi框架的类加载器:Osgi框架实现了一套新的类加载器机制,允许同级之间委托进行类的加载。在Osgi中,每个Bundle都有自己的类加载器,当需要加载类时,会先在自己的存储空间中查找,如果找不到,则委托给父级Bundle的类加载器进行查找。这种机制打破了传统的双亲委派模型。

二、线程上下文类加载器

双亲委派机制是Java类加载器的一个重要特性,它保证了Java核心API的稳定性和防止了类冲突。然而,在某些情况下,可能需要打破这种机制。接下来将重点探讨如何通过线程上下文类加载器来实现这一点,并以JDBC中的驱动加载为例进行深入解析。

线程上下文类加载器(Thread Context ClassLoader,TCCL)是Java中一种特殊的类加载器,用于处理多线程环境下的类和资源加载问题。它确保了每个线程都能维护自己的类加载器上下文,从而实现了线程安全。线程上下文类加载器是解决线程局部变量和类加载问题的有效机制。当线程需要加载类时,它会首先使用与其关联的上下文类加载器,从而确保了类加载的一致性和正确性。

1.JDBC线程上下文类加载器案例

在JDBC中,DriverManager用于管理不同数据库的驱动。例如,MySQL的驱动和Oracle的驱动。DriverManager类位于rt.jar包中,由启动类加载器加载。然而,用户JAR包中的驱动需要由应用程序类加载器来加载,这就违反了双亲委派机制。

image.gif

为了解决这个问题,JDBC采用了SPI(Service Provider Interface)机制。SPI是一种JDK内置的服务提供发现机制。

在ClassPath路径下的META-INF/services文件夹中,以接口的全限定名来命名文件名,对应的文件中写该接口的实现:

例如,在MySQL JDBC驱动中,有一个名为java.sql.Driver的文件在META-INF/services文件夹中,文件内容为com.mysql.cj.jdbc.Driver。这样,当DriverManager需要加载MySQL驱动时,它会首先查看当前线程的上下文类加载器(通常是应用程序类加载器)是否能加载这个驱动。由于驱动的实现类是由应用程序类加载器加载的,这就打破了双亲委派机制。

image.gif

image.gif

使用ServiceLoader加载实现类:

使用ServiceLoader加载对应的Driver对象:

ServiceLoader<Driver> serviceLoader = ServiceLoader.load(Driver.class);

image.gif

在这个过程中,DriverManager使用了SPI机制来加载jar包中对应的驱动类。SPI机制通过在META-INF/services目录下查找实现了特定接口的类的配置文件,并使用线程上下文类加载器来加载这些实现类。

image.gif

SPI机制中使用的线程上下文类加载器通常是应用程序类加载器。这是因为线程上下文类加载器是线程特有的,每个线程都可以关联一个不同的上下文类加载器。这使得SPI机制能够灵活地加载类,打破了双亲委派机制的限制。

在ServiceLoader的load方法中,通过获取当前线程的上下文类加载器来实现类的加载。

public static <S> ServiceLoader<S> load(Class<S> var0) {
        ClassLoader var1 = Thread.currentThread().getContextClassLoader();
        return load(var0, var1);
    }

image.gif

image.gif

为了验证线程上下文类加载器的使用,可以创建一个新的线程并在其中打印线程上下文类加载器的信息。

public class NewThreadDemo {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getContextClassLoader());
            }
        }).start();
    }
}

image.gif

运行结果(应用程序类加载器):

image.gif

完整流程分析

  1. 启动类加载器加载DriverManager。
  2. 在初始化DriverManager时,通过SPI机制加载jar包中的myql驱动。
  3. SPI中利用了线程上下文类加载器(应用程序类加载器)去加载类并创建对象。

image.gif

这种由启动类加载器加载的类,委派应用程序类加载器去加载类的方式,打破了双亲委派机制。


总结

JVM是Java程序的运行环境,负责字节码解释、内存管理、安全保障、多线程支持、性能监控和跨平台运行。本文主要介绍了打破双亲委派机制的方法、线程上下文类加载器等内容,希望对大家有所帮助。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3天前
|
缓存 安全 Java
7张图带你轻松理解Java 线程安全,java缓存机制面试
7张图带你轻松理解Java 线程安全,java缓存机制面试
|
5天前
|
前端开发 安全 Java
深入浅出JVM(八)之类加载器
深入浅出JVM(八)之类加载器
|
5天前
|
Arthas Prometheus 监控
JVM工作原理与实战(四十四):JVM常见题目
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了JVM常见题目等内容。
20 1
|
5天前
|
存储 监控 算法
JVM工作原理与实战(四十三):JVM常见题目
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了JVM常见题目等内容。
14 1
|
5天前
|
存储 监控 Oracle
JVM工作原理与实战(四十二):JVM常见题目
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了JVM常见题目等内容。
15 2
|
5天前
|
存储 监控 算法
JVM工作原理与实战(四十一):ShenandoahGC原理
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了ShenandoahGC、ShenandoahGC 1.0版本、ShenandoahGC 2.0版本、ShenandoahGC执行流程等内容。
11 0
|
5天前
|
存储 监控 安全
JVM工作原理与实战(四十):ZGC原理
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了ZGC、ZGC核心技术、ZGC的内存划分、ZGC的执行流程、分代ZGC的设计等内容。
18 1
|
5天前
|
监控 算法 安全
JVM工作原理与实战(三十九):G1垃圾回收器原理
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了G1垃圾回收器执行流程、年轻代回收原理、卡表(Card Table)、记忆集的生成流程、年轻代回收的详细步骤、混合回收的步骤、初始标记、并发标记、SATB、转移等内容。
23 0
|
5天前
|
监控 安全 Java
JVM工作原理与实战(三十八):JIT即时编译器原理
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了JIT即时编译器、HotSpot中的JIT编译器、JIT优化技术、JIT优化建议等内容。
15 0
|
5天前
|
监控 Java Linux
JVM工作原理与实战(三十七):Shenandoah GC和ZGC
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了垃圾回收器的技术演进、Shenandoah GC、ZGC等内容。
18 0