【jvm】通过JDBC为例谈谈双亲委派模型的破坏

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 双亲委派模型并不是一个强制约束模型,而是java设计者推荐给开发者的类加载实现方式;但是也会有例外; 今天我们主要来讲一讲 类似于SPI这种设计导致的双亲委派模型被“破坏”的情况;

我们都知道类加载的双亲委派模型双亲委派模型并不是一个强制约束模型,而是java设计者推荐给开发者的类加载实现方式;但是也会有例外; 今天我们主要来讲一讲  类似于SPI这种设计导致的双亲委派模型被“破坏”的情况;

JDBC

不破坏双亲委派模型的情况(不使用JNDI服务)

// 1.加载数据访问驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.连接到数据"库"上去
        Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=GBK", "root", "");
Class.forName("com.mysql.cj.jdbc.Driver"); 这句会主动去加载类com.mysql.cj.jdbc.Driver
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}

可以看到,Class.forName()其实触发了静态代码块,然后向DriverManager中注册了一个mysql的Driver实现。 这个时候,我们通过DriverManager去获取connection的时候只要遍历当前所有Driver实现,然后选择一个建立连接就可以了

破坏双亲委派模型的情况

在JDBC4.0以后,开始支持使用spi的方式来注册这个Driver,具体做法就是在mysql的jar包中的META-INF/services/java.sql.Driver 文件中指明当前使用的Driver是哪个,然后使用的时候就直接这样就可以了

Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=GBK", "root", "");

可以看到这里直接获取连接,省去了上面的Class.forName()注册过程。 现在,我们分析下看使用了这种spi服务的模式原本的过程是怎样的:

在这里插入图片描述

  1. 从META-INF/services/java.sql.Driver文件中获取具体的实现类名“com.mysql.cj.jdbc.Driver”
  2. 加载这个类,用class.forName("com.mysql.jdbc.Driver")来加载

Class.forName()加载用的是调用者的Classloader, 这个调用者DriverManager是在rt.jar中的,ClassLoader是启动类加载器,而com.mysql.jdbc.Driver肯定不在<JAVA_HOME>/lib下,所以肯定是无法加载mysql中的这个类的。这就是双亲委派模型的局限性了,父级加载器无法加载子级类加载器路径中的类。

如何解决父加载器无法加载子级类加载器路径中的类

我们分析一下,想要正常的加载,启动类加载器肯定不能加载,那么只能用应用类加载器能够加载,那么如果有什么办法能够获取到应用类加载器就可以解决问题了;我们看看 jdk是怎么做的;

线程上下文类加载器

public class DriverManager {
    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }
    private static void loadInitialDrivers() {
        //省略代码
        //这里就是查找各个sql厂商在自己的jar包中通过spi注册的驱动
        ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
        Iterator<Driver> driversIterator = loadedDrivers.iterator();
        try{
             while(driversIterator.hasNext()) {
                driversIterator.next();
             }
        } catch(Throwable t) {
                // Do nothing
        }
        //省略代码
    }
}

看这里,加载的时候去获取了一个加载器

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

获取线程上下文类加载器Thread.currentThread().getContextClassLoader(); 这个值如果没有特定设置,一般默认使用的是应用程序类加载器;

总结

为了实现SPI这种模式,实现可插拔 做出了不符合双亲委派原则行为,但是这种破坏并不具备贬义的感情色彩,只要有足够意义和理由,突破已有的原则就可以认为是一种创新;

对于线程上下文类加载器  的实现类似于ThreadLocal 将变量传递到整个线程的生命周期; 这里无非就是将ThreadLocal里面存放的是应用类加载器;

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
8月前
|
安全 Java
对 JVM 的类加载机制以及寻找字节码文件的“双亲委派模型”的理解
对 JVM 的类加载机制以及寻找字节码文件的“双亲委派模型”的理解
49 0
|
4月前
|
安全 Java 应用服务中间件
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
什么是类加载器,类加载器有哪些;什么是双亲委派模型,JVM为什么采用双亲委派机制,打破双亲委派机制;类装载的执行过程
120 35
JVM常见面试题(三):类加载器,双亲委派模型,类装载的执行过程
|
8月前
|
Java 关系型数据库 MySQL
【JVM】JDBC案例打破双亲委派机制
【JVM】JDBC案例打破双亲委派机制
192 4
|
3月前
|
Java
【JVM】双亲委派模型
【JVM】双亲委派模型
32 1
|
8月前
|
存储 算法 Oracle
深入理解 JVM(重点:双亲委派模型 + 垃圾回收算法)
深入理解 JVM(重点:双亲委派模型 + 垃圾回收算法)
|
8月前
|
Java
一篇博客带你了解JVM中的双亲委派模型
一篇博客带你了解JVM中的双亲委派模型
|
8月前
|
存储 Java C++
JVM内存模型和结构详解(五大模型图解)
JVM内存模型和结构详解(五大模型图解)
|
8月前
|
存储 安全 Java
JVM类加载(类加载过程、双亲委派模型)
JVM类加载(类加载过程、双亲委派模型)
|
存储 安全 Java
JVM学习.04. Java内存模型与线程模型
该篇内容主要介绍JVM如何实现多线程,多线程间由于共享和竞争数据而导致的一系列问题以及解决方案。
281 1
JVM学习.04. Java内存模型与线程模型
|
前端开发 Java 应用服务中间件
【Java虚拟机】JVM类加载机制和双亲委派模型
【Java虚拟机】JVM类加载机制和双亲委派模型
【Java虚拟机】JVM类加载机制和双亲委派模型