双亲委派机制,懂吧~ 那什么情况下需要破坏它,知道吗?

news2024/11/18 3:46:40

一、什么是双亲委派机制?

我们要获得一个类的Class实例,可以采用如下方式:

那么在Class的forName(className)方法中,会根据是谁调用了Class.forName(className)这个方法,那么就获得当时加载了它的那个ClassLoader,然后,再通过类加载器来负责对类进行加载操作。

获得了类加载器之后,就可以通过如下的loadClass(...)方法对className执行类加载操作的。那么在如下的代码逻辑中,可以看到双亲委派机制的逻辑了。也就是说,如果自己没有加载过className这个类,则必须“委托”给父加载器执行加载操作。除非父类加载器无法加载这个类,才由自己执行加载操作

那么,为什么父类加载器无法加载某个类呢?原因就是,每个类型的加载器z都有其约束的加载路径,如果这个className没有在这个路径下,那么对应的类加载器就无法加载这个类了。如下所示:

二、什么情况下,需要破坏双亲委派机制?

我们以使用JDBC操作数据库时的代码为例:

public class JdbcTest {
    public static void main(String[] args) {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/seata?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true", "root", "root");
        ... ...
    }
}

【解释】由于是JdbcTest类调用了Class.forName方法,并且JdbcTest类是由AppClassLoader加载的,所以先由AppClassLoader去查找自己是否加载过类"com.mysql.jdbc.Driver",发现没有加载过,那么委托ExtClassLoader去加载,而它之前也没有加载过这个类,那么委托给BootstrapClassLoader去加载,但是由于com.mysql.jdbc.Driver这个类在CLASSPATH中,而不在rt.jarext/*.jar里,所以最终还是会由AppClassLoader去加载。

当"com.mysql.jdbc.Driver"这个类加载后,就会执行它内部的静态方法,将new Driver()实例对象注册到DriverManager中,这样就完成了驱动注册操作。

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {}

    // 静态块执行语句
    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

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

那么,我们以往的数据库连接代码就可以改成这样:

public class JdbcTest {
    public static void main(String[] args) {
        // Class.forName("com.mysql.jdbc.Driver"); // 此处就不需要显示通过Class.forName(...)执行类的加载操作了
        Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/seata?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true", "root", "root");
        ... ...
    }
}

这个不对啊?Driver在哪加载了呢?我们来看一下DriverManager类(JDK8)的静态方法就知道了。如下所示:

static {
    loadInitialDrivers(); // 加载初始化驱动器
    println("JDBC DriverManager initialized");
}

private static void loadInitialDrivers() {
    String drivers;
    try {
        drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
            public String run() {
                return System.getProperty("jdbc.drivers");
            }
        });
    } catch (Exception ex) {drivers = null;}

    AccessController.doPrivileged(new PrivilegedAction<Void>() {
        public Void run() {
            ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class); // 使用SPI加载Driver
            Iterator<Driver> driversIterator = loadedDrivers.iterator();
            try{
                while(driversIterator.hasNext()) {
                    driversIterator.next();
                }
            } catch(Throwable t) {}
            return null;
        }
    });
    
    if (drivers == null || drivers.equals("")) return;
    
    String[] driversList = drivers.split(":");
    for (String aDriver : driversList) {
        try {
            Class.forName(aDriver, true, ClassLoader.getSystemClassLoader());
        } catch (Exception ex) {
            println("DriverManager.Initialize: load failed: " + ex);
        }
    }
}

【解释】在上面的代码中,我们看到了ServiceLoader.load(Driver.class)这行代码,它是基于SPI的方式去加载了Driver实例了。

那为啥要这么做呢?直接在DriverManager中编写Class.forName("com.mysql.cj.jdbc.Driver")这行代码不就可以了嘛,采用SPI难道是为了炫技嘛?

其实不是的,因为DriverManager这个类的全路径名是java.sql.DriverManager,它是在rt.jar包中的,所以它是由BootstrapClassLoader负责加载的。而com.mysql.cj.jdbc.Driver类不在rt.jar包中,所以BootstrapClassLoader无法加载,而BootstrapClassLoader又是顶层的类加载器了,它没有父加载器,所以既无法委托给父加载器负责加载,而自己又无法加载,那么就只能报错ClassNotFoundException了。

那这个问题怎么解决呢?SPI的出现解决了这个问题,下面我们来看一下SPI是如何处理的,即:

ServiceLoader.load(Driver.class);

那么问题又来了,这个Thread.currentThread().getContextClassLoader()是从当前线程的上下文中获得了ClassLoader,那到底_这个ClassLoader是什么呢?_想要找到答案,我们就需要看Launcher类了,它是负责用来创建类加载器的。

【解释】从上面代码我们可以看到,当前线程的上下文中获得的ClassLoader就是AppClassLoader,那么它加载的类路径就是CLASSPATH,就可以成功的加载"com.mysql.cj.jdbc.Driver"这个类了。它采用的这种方式,就是破坏双亲委托机制来加载Driver类了。

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。

更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/899126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp选择只选择月份demo效果(整理)

<template><view style"margin-top: 200rpx;"><!-- mode"multiSelector" 多列选择器 --><view><picker :range"years" :value"echoVal" change"yearChange" mode"multiSelector">{…

【面试题】2、Docker和Spring相关

1、Docker是什么&#xff1f; &#xff08;1&#xff09;Docker是一个快速交互、运行应用的技术&#xff0c;可以将程序及其依赖、运行环境一起打包为一个镜像&#xff0c;该镜像可以迁移到任意的Linux操作系统 &#xff08;2&#xff09;运行时利用沙箱机制形成隔离容器&…

【JasperReports笔记04】如何使用Jasper Studio制作父子报表,并且通过Java + Parameters参数填充模板文件

这篇文章&#xff0c;主要介绍如何使用Jasper Studio制作父子报表&#xff0c;并且通过Java Parameters参数填充模板文件。 目录 一、JasperReports实现父子报表 1.1、运行效果 1.2、制作模板 &#xff08;1&#xff09;制作子报表 &#xff08;2&#xff09;制作子报表的…

计算机竞赛 图像检索算法

文章目录 1 前言2 图像检索介绍(1) 无监督图像检索(2) 有监督图像检索 3 图像检索步骤4 应用实例5 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 图像检索算法 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff…

0101读写分离测试-jdbc-shardingsphere-中间件

文章目录 1 前言2、创建SpringBoot程序2.1、创建项目2.2、添加依赖2.3、生成实体类、service与Mapper1.5、配置读写分离 2、测试2.1、读写分离测试2.2、事务测试2.3、负载均衡测试 结语 1 前言 shardingshpere-jdbc定位为轻量级 Java 框架&#xff0c;在 Java 的 JDBC 层提供的…

处理Selenium3+python3定位鼠标悬停才显示的元素

这篇文章主要介绍了Selenium3python3--如何定位鼠标悬停才显示的元素 &#xff0c;文中通过简单代码给大家介绍的非常详细,需要的朋友可以参考下 先给大家介绍下Selenium3python3--如何定位鼠标悬停才显示的元素 定位鼠标悬停才显示的元素&#xff0c;要引入新模块 # coding…

Tableau画图

目录 蝴蝶图 四象图 排序图 盒型图/散点图 圆环图 火柴图 直方图 瀑布图 地理图 面积图 树地图 面积图 条形图 词云图 双轴图 填充地图 tableau2023.2 须知 蝴蝶图 拉好数据之后 创建新字段正负销售额&#xff0c;并拖入第一个颜色标记卡 四象图 智能推荐 散…

使用句子嵌入的无监督文本摘要

一、说明 这是一个AI研究生班的作业练习&#xff0c; 在本文中&#xff0c;我将描述我用来在 Python 中执行文本摘要的方法&#xff0c;这是我在导师分配给我的很棒的任务列表之一。 二、什么是文本摘要&#xff1f; 文本摘要是从一个或多个源中提取最重要的信息以生成特定用户…

华为ENSP网络设备配置实战4(OSPF+BGP+VPN+单臂路由)

题目要求 1、loopback口通过OSPF连通&#xff0c;合理规划OSPF开销&#xff0c;通过设置AR1->AR2->AR4链路&#xff0c;来消除负载链路。 2、AR3、AR4分别与AR1、AR2建立BGP邻居 3、AR3、AR4作为PC机网关设备 4、PC1、PC3由VPN-spi承载&#xff0c;PC2、PC4由VPN-spims承…

【算法挨揍日记】day03——双指针算法_有效三角形的个数、和为s的两个数字

611. 有效三角形的个数 611. 有效三角形的个数https://leetcode.cn/problems/valid-triangle-number/ 题目描述&#xff1a; 给定一个包含非负整数的数组 nums &#xff0c;返回其中可以组成三角形三条边的三元组个数。 解题思路&#xff1a; 本题是一个关于三角形是否能成立…

通过爬虫抓取上市企业利润表并在睿思BI中展示

睿思BI从v5.3开始支持网络爬虫&#xff0c;可以从指定URL抓取表格数据&#xff0c;本示例实现从网络上抓取上市企业招商银行的利润表数据&#xff0c;并在睿思BI中进行展现。 首先&#xff1a;从搜狐财经抓取招商银行利润表数据&#xff0c;操作过程如下&#xff1a; 1.在睿思…

提示词4大经典框架;将AI融入动画工作流的案例和实践经验;构建基于LLM的系统和产品的模式;提示工程的艺术 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 高效提示词的4大经典框架&#xff1a;ICIO、CRISPE、BROKE、RASCEF ICIO 框架 Intruction (任务) &#xff1a;你希望AI去做的任务&am…

软件测试中如何测试算法?

广义的算法是指解决问题的方案,小到求解数学题,大到制定商业策略,都可以叫做算法。而我们 今天讨论的软件测试中的算法,对应的英文单词为Algorithm ,专指计算机处理复杂问题的程序或 指令。 随着最近几年人工智能等领域的快速发展,算法受到前所未有的重视,算法测试也随之兴起。…

异步电机IM-改进的电压模型磁链观测器学习

导读&#xff1a;本期文章主要介绍异步电机的改进型电压模型磁链观测器。传统纯积分形式的积分器在低速区域存在初始值问题和直流偏置问题&#xff0c;所以在实际应用中必须对电压模型进行改进。本期文章中的对电压模型改进是借鉴一篇IEEE中的方法。 如果需要文章中对应的仿真…

gcc make cmake ninja的区别

理清C编译过程用到的工具概念 ref: 知乎 早先学C的时候&#xff0c;因为只需要点击IDE的运行按钮&#xff0c;程序就可以跑起来&#xff0c;写过最复杂的只不过是几个文件的学生管理系统。 现在要重新拾起C&#xff0c;看的项目和之前的不可同日而语&#xff0c;构建系统也复…

最优化方法Python计算:牛顿算法

设函数 f ( x ) f(\boldsymbol{x}) f(x)&#xff0c; x ∈ R n \boldsymbol{x}\in\text{ℝ}^n x∈Rn二阶连续可微&#xff0c;记 g ( x ) ∇ f ( x ) \boldsymbol{g}(\boldsymbol{x})\nabla f(\boldsymbol{x}) g(x)∇f(x)&#xff0c; H ( x ) ∇ 2 f ( x ) \boldsymbol{H}(\…

【数据结构OJ题】用栈实现队列

原题链接&#xff1a;https://leetcode.cn/problems/implement-queue-using-stacks/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 用两个栈实现&#xff0c;一个栈进行入队操作&#xff0c;另一个栈进行出队操作。 出队操作&#xff1a; 当出队的栈…

ARFoundation避坑记录

网上很多人说这个要改成可选的&#xff0c;否则如果没有安装arcore就会自动弹窗&#xff0c;但是如果关闭了&#xff0c;确实不会弹窗了&#xff0c;但是检测设备的代码也不能完美执行了&#xff0c;如果设备安装了arcore还好&#xff0c;如果没有安装测无法检测。 如果不想有…

常见的CRM系统报价

一个CRM系统大概多少钱&#xff1f;CRM系统的价格因为不同的厂商、功能、部署方式、用户数等因素而有很大的差异&#xff0c;没有一个固定的标准。但是&#xff0c;我们可以根据一些常见的CRM软件的报价&#xff0c;对CRM价格有一个大致的了解。 一、CRM的部署方式 CRM系统的…

填充柄功能

单元格右下角十字符号 顺序式填充 输入1,2&#xff0c;直接拉取即可实现顺序1到10. 复制式填充 CtrlD或者拉取&#xff0c;选择右下角复制单元格。 规律式填充 输入星期一&#xff0c;星期二&#xff0c;下拉一直可以到星期日 自定义填充 选择文件-》选项-》自定义序列 输…