当前位置: 首页 > article >正文

打破双亲委派模型的实践:JDBC与Tomcat的深度解析

一、JDBC如何打破双亲委派模型

1. JDBC SPI机制的核心矛盾

Java数据库连接(JDBC)是打破双亲委派模型的经典案例,其根本原因在于基础类库需要加载实现类的矛盾:

  • 核心接口位置java.sql.Driver等接口位于rt.jar中,由启动类加载器加载
  • 驱动实现位置:MySQL/Oracle等数据库驱动位于应用classpath下,应由应用类加载器加载

按照标准双亲委派模型,启动类加载器加载的类无法"看到"应用类加载器加载的类,这就形成了加载死结。

2. 解决方案:线程上下文类加载器(Thread Context ClassLoader)

JDBC通过以下机制打破双亲委派:

// ServiceLoader.load()的核心逻辑
public static <S> ServiceLoader<S> load(Class<S> service) {ClassLoader cl = Thread.currentThread().getContextClassLoader();return new ServiceLoader<>(Reflection.getCallerClass(), service, cl);
}

具体实现步骤

  1. DriverManager(由启动类加载器加载)初始化时,通过ServiceLoader加载驱动
  2. 使用当前线程的上下文类加载器(默认为应用类加载器)来加载META-INF/services下的驱动实现
  3. 通过Class.forName(driverClass, false, loader)显式指定类加载器

3. 类加载时序图

[启动类加载器]↑
[DriverManager.loadInitialDrivers()]↓ (通过线程上下文类加载器)
[应用类加载器]↓
[加载META-INF/services/java.sql.Driver]↓
[加载具体驱动实现类如com.mysql.jdbc.Driver]

4. 为什么必须打破双亲委派?

如果严格遵守双亲委派:

  • 启动类加载器无法加载第三方驱动(不在$JAVA_HOME/lib下)
  • 应用类加载器加载的驱动无法被DriverManager识别(类型不匹配)

二、Tomcat如何打破双亲委派模型

1. Tomcat的类加载器架构

Tomcat设计了复杂的类加载体系来解决Web应用隔离问题:

      Bootstrap↑System↑Common↗ ↖
Webapp1   Webapp2
  • Common ClassLoader:加载Tomcat自身和所有Web应用共享的类
  • Webapp ClassLoader:每个Web应用独有,优先加载/WEB-INF/classes/WEB-INF/lib下的类

2. 打破双亲委派的实现方式

Tomcat通过以下机制实现类加载隔离:

(1) 逆向委派(先自己后父类)
// WebappClassLoader.findClass()逻辑
protected Class<?> findClass(String name) throws ClassNotFoundException {// 1. 首先检查本地仓库Class<?> clazz = findClassInternal(name);if (clazz != null) return clazz;// 2. 检查JVM缓存clazz = findLoadedClass0(name);if (clazz != null) return clazz;// 3. 最后才委托给父加载器return super.findClass(name);
}
(2) 资源加载的隔离实现
// WebappClassLoader.getResource()逻辑
public URL getResource(String name) {// 1. 首先检查本地资源URL url = findResourceInternal(name);if (url != null) return url;// 2. 检查父类资源(逆向双亲委派)if (parent != null) {url = parent.getResource(name);}// 3. 最后尝试系统类加载器if (url == null) {url = system.getResource(name);}return url;
}

3. 典型应用场景

场景1:Web应用库隔离
  • 应用A使用Spring 4.x
  • 应用B使用Spring 5.x
  • 通过独立的WebappClassLoader实现版本共存
场景2:热部署实现
// 热部署关键代码
WebappClassLoader loader = new WebappClassLoader(parent);
loader.setRepository(new String[] { "/path/to/updated/classes" });
context.setLoader(loader);

4. 打破双亲委派的必要性

  1. 类库隔离需求:不同Web应用可能需要相同类库的不同版本
  2. 安全隔离需求:防止Web应用访问Tomcat内部类
  3. 资源隔离需求:确保每个Web应用的静态资源独立
  4. 热部署支持:需要能重新加载修改后的类而不重启容器

三、两种打破方式的对比分析

特性JDBC方式Tomcat方式
打破动机基础架构需要加载实现类应用隔离和热部署需求
技术实现线程上下文类加载器自定义类加载器+逆向查找
影响范围局部性(特定服务的加载)全局性(整个应用的类加载体系)
Java标准支持通过ServiceLoader规范支持完全自定义实现
典型应用所有SPI扩展场景应用服务器/模块化系统

四、实践中的注意事项

  1. JDBC最佳实践

    // 正确设置上下文类加载器
    Thread.currentThread().setContextClassLoader(original);
    try {// JDBC操作
    } finally {Thread.currentThread().setContextClassLoader(original);
    }
    
  2. Tomcat调优建议

    <!-- 配置delegate="true"可恢复标准双亲委派 -->
    <Context delegate="true"><Loader delegate="true"/>
    </Context>
    
  3. 常见问题排查

    • ClassCastException:检查类是否被不同加载器加载
    • NoClassDefFoundError:检查类加载器委托链
    • 内存泄漏:注意WebappClassLoader的生命周期管理

大白话理解:"启动类加载器加载的类无法"看到"应用类加载器加载的类

类加载器就像“找书的规矩”

想象Java程序运行就像一群人(类)在图书馆(JVM)里找书(类文件)。这个图书馆有个规矩:“先问长辈,长辈找不到,自己再找”

  1. 启动类加载器(Bootstrap)
    是图书馆的馆长,只管最核心的书(比如Java自带的StringInteger这些书),而且馆长不认识任何其他员工

  2. 应用类加载器(AppClassLoader)
    是普通员工,负责找用户自己写的书(比如你写的MyClass)。他会先问上级(馆长),馆长说“我没这本书”,他才自己去找。


为什么馆长看不到员工的书?

  • 规矩就是“只往上问,不往下问”
    员工(AppClassLoader)会问馆长(Bootstrap):“你有这本书吗?”,但馆长从来不会反过来问员工:“你有啥书?”
    → 所以馆长根本不知道员工手里有什么书。

  • 安全考虑
    如果馆长能随便拿员工的书,万一员工的书里有毒(比如有人恶意改写了String类),整个图书馆就乱套了。所以Java规定:核心的书只能馆长管,员工的书馆长不碰


举个栗子🌰

你写了一个类叫Cat.java,打包成程序运行:

  1. JVM先让**员工(AppClassLoader)**去找Cat
  2. 员工按规矩先问馆长:“馆长,你有Cat吗?”
    馆长(Bootstrap)说:“我只有java.lang这种书,没有Cat!”
  3. 员工只好自己去找,找到了Cat

但反过来:
如果馆长(Bootstrap)在加载java.lang.String时,绝不会问员工:“你有String吗?” —— 因为馆长默认自己管所有核心的书,不需要问别人。


一句话总结

“启动类加载器(馆长)不认识应用类加载器(员工)的书,因为Java的规矩是:员工可以问馆长,但馆长不能问员工。”
这样设计是为了防止核心代码被乱改,保证Java程序稳定运行。

相关文章:

打破双亲委派模型的实践:JDBC与Tomcat的深度解析

一、JDBC如何打破双亲委派模型 1. JDBC SPI机制的核心矛盾 Java数据库连接(JDBC)是打破双亲委派模型的经典案例&#xff0c;其根本原因在于基础类库需要加载实现类的矛盾&#xff1a; 核心接口位置&#xff1a;java.sql.Driver等接口位于rt.jar中&#xff0c;由启动类加载器…...

《打破枷锁:Python多线程GIL困境突围指南》

GIL&#xff0c;这个Python解释器层面的独特机制&#xff0c;虽在一定程度上守护了内存管理的秩序&#xff0c;却也成为了多线程并行的紧箍咒&#xff0c;限制了Python在多核处理器上的性能发挥。今天&#xff0c;让我们深入剖析GIL的本质&#xff0c;探寻突破这一枷锁的有效策…...

Java并发编程:全面解析锁策略、CAS与synchronized优化机制

一、六种锁策略场景化解析 1. 乐观锁 vs 悲观锁&#xff1a;图书馆借书的两种策略 核心差异&#xff1a;对资源是否会被抢占的预期不同。 乐观锁&#xff08;假设冲突概率低&#xff09; → 行为&#xff1a;直接去书架上拿书&#xff08;围绕加锁要做的工作更少&#xff09…...

2025第三届黄河流域网络安全技能挑战赛--Crypto--WriteUp

2025第三届黄河流域网络安全技能挑战赛–Crypto–WriteUp Crypto sandwitch task from Crypto.Util.number import * import gmpy2 flag bflag{fake_flag} assert len(flag) 39 p getPrime(512) q getPrime(512) n p * q e 0x3 pad1 beasy_problem pad2 bHow_to_so…...

[爬虫知识] IP代理

相关实战案例&#xff1a;[爬虫实战] 代理爬取&#xff1a;小白也能看懂怎么用代理 相关爬虫专栏&#xff1a;JS逆向爬虫实战 爬虫知识点合集 爬虫实战案例 引言&#xff1a;爬虫与IP封锁的攻防战 对网络爬虫而言&#xff0c;遇到的一个较棘手的问题就是封IP&#xff1a;请…...

6个月Python学习计划 Day 1 - Python 基础入门 开发环境搭建

6个月Python学习计划&#xff1a;从入门到AI实战&#xff08;前端开发者进阶指南&#xff09; &#x1f3af; 今日目标 理解 Python 的背景和用途安装 Python 开发环境熟悉基本语法&#xff1a;变量、数据类型、打印输出动手编写第一个 Python 程序 &#x1f9e0; 学习内容详…...

GraphPad Prism工作表的基本操作

《2025新书现货 GraphPad Prism图表可视化与统计数据分析&#xff08;视频教学版&#xff09;雍杨 康巧昆 清华大学出版社教材书籍 9787302686460 GraphPadPrism图表可视化 无规格》【摘要 书评 试读】- 京东图书 GraphPad Prism中包含5种工作表&#xff0c;每种工作表的基本操…...

Maven插件之docker-maven-plugin

介绍 在持续集成过程中&#xff0c;项目工程一般使用 Maven 编译打包&#xff0c;然后生成镜像&#xff0c;通过镜像上线&#xff0c;能够大大提供上线效率&#xff0c;同时能够快速动态扩容&#xff0c;快速回滚&#xff0c;着实很方便。docker-maven-plugin 插件就是为了实现…...

成年后还能学习多少知识,由大脑的这个数量决定

撰文&#xff5c;Anne Trafton 编译&#xff5c;郑添惺 审校&#xff5c;clefable 麻省理工学院&#xff08;MIT&#xff09;的一些神经科学家发现&#xff0c;成年的大脑中含有数百万个“静默突触”&#xff08;silent synapses&#xff09;。它们是神经元之间未成熟的神经突…...

Flask 会话管理:从原理到实战,深度解析 session 机制

1、Flask中session 的实现原理&#xff1a;服务器与客户端的协作 HTTP 协议是无状态的——服务器无法区分两次请求是否来自同一用户。这意味着&#xff0c;用户登录后跳转到其他页面时&#xff0c;服务器会“忘记”用户身份。 为解决这一问题&#xff0c;Web 开发中引入了会话…...

MySQL连接错误解决方案:Can‘t connect to MySQL server on ‘localhost‘ (10038)

错误描述 当您尝试连接MySQL数据库时&#xff0c;可能会遇到以下错误提示&#xff1a; 这个错误表明客户端无法连接到本地MySQL服务器。 可能的原因 MySQL服务未启动 MySQL配置问题 防火墙或安全软件阻止连接 端口被占用或未正确配置 网络连接问题 解决方案 方法一&am…...

【跨端框架检测】使用adb logcat检测Android APP使用的跨端框架方法总结

目录 Weex 跨端框架使用了uni-app的情况区分使用了uni-app还是Weex 判断使用了Xamarin判断使用了KMM框架判断使用了 ​​Ionic 框架判断使用了Cordova框架判断使用了Capacitor 框架使用了React Native框架使用了QT框架使用了Cocos框架使用了Electron 框架使用了flutter 框架使用…...

lua脚本实战—— Redis并发原子性陷阱

需求分析 对于内容类网站&#xff0c;比如用户浏览题目的答案&#xff0c;需要先登录才能追溯&#xff0c;那么可以统计用户访问频率来限制数据的爬取。 可采用分级反爬虫策略&#xff0c;先告警、再采取强制措施&#xff1a; 如果每分钟超过 10 道题&#xff0c;给管理员发…...

【MySQL】第10节|MySQL全局优化与Mysql 8.0新增特性详解

全局优化 mysql server参数 1. max_connections&#xff08;最大连接数&#xff09; 含义&#xff1a;MySQL 服务允许的最大并发连接数&#xff08;包括正在使用和空闲的连接&#xff09;。超过此限制时&#xff0c;新连接会被拒绝&#xff08;报错 Too many connections&am…...

CSS相关知识

1.清除浮动的方法 2.定位 静态定位相当于标准流 相对定位不脱离文档流&#xff0c;仍然占据原来的位置&#xff08;最频繁的作用是给绝对定位当爹&#xff09; 绝对定位脱离文档标准流&#xff0c;不再占有原来位置 3.BFC 1. 解决浮动元素导致的父容器高度塌陷 2. 阻止相邻元…...

AI扫描王APP:高效便捷的手机扫描工具,让生活更智能

AI扫描王APP是一款功能强大的手机扫描软件&#xff0c;专为追求高效、便捷的用户设计。它不仅支持文字提取和扫描翻译&#xff0c;还能进行测量&#xff0c;满足用户在不同场景下的需求。无论是办公、学习还是日常使用&#xff0c;AI扫描王都能帮助你快速完成任务&#xff0c;节…...

《仿盒马》app开发技术分享-- 原生地图展示(端云一体)

开发准备 上一节我们实现了获取当前用户的位置&#xff0c;并且成功的拿到了经纬度&#xff0c;这一节我们就要根据拿到的经纬度&#xff0c;结合我们其他的知识点来实现地图的展示。 功能分析 地图的展示&#xff0c;我们需要在管理中心先给我们对应的应用开启地图api功能&…...

Linux 操作文本文件列数据的常用命令

文章目录 Linux 操作文本文件列数据的常用命令基本列处理命令高级列处理列数据转换和排序列数据统计和分析 Linux 操作文本文件列数据的常用命令 Linux 提供了多种强大的命令来处理文本文件中的列数据&#xff0c;以下是一些最常用的命令和工具&#xff1a; 基本列处理命令 c…...

IP、子网掩码、默认网关、DNS

IP、子网掩码、默认网关、DNS 1. 概述1.1 windows配置处 2.IP 地址&#xff08;Internet Protocol Address&#xff09;2.1 公网ip2.2 内网ip2.3 &#x1f310; 公网 IP 与内网 IP 的关系&#xff08;NAT&#xff09; 3. 子网掩码&#xff08;Subnet Mask&#xff09;4. 默认网…...

华为OD机试真题——字符串加密 (2025B卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 B卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…...

角度回归——八参数检测四边形Gliding Vertex

文章目录 一、介绍&#xff08;一&#xff09;五参数检测方法&#xff08; 基于角度&#xff09;&#xff08;二&#xff09;八参数检测方法&#xff08;point-based&#xff09;的边界 二、方案分析&#xff08;一&#xff09;问题定义&#xff08;二&#xff09;方案&#xf…...

JVM 高质量面试题

&#x1f4cc; 文章目录 一、JVM 内存结构与运行时模型1. JVM 内存结构分区及作用2. 栈帧结构及方法调用链维护3. 逃逸分析及其对对象分配策略的影响4. TLAB 的作用及提升对象创建效率的机制 二、垃圾回收器与 GC 调优1. CMS 与 G1 垃圾收集器的设计区别及适用场景2. Full GC 频…...

AI助力,制作视频裁剪软件

1. 视频裁剪软件套路多 最近再做一些测试&#xff0c;经常需要录屏什么的&#xff0c;有时候录制的时长视频&#xff0c;需要裁剪&#xff0c;比如去掉开头一些帧或者结尾的一些帧&#xff0c;就想保留关键点。但是网上下的一些软件&#xff0c;打开一用都是要付费的。所以想着…...

SQL注入基础

普通sql注入:后台能提供有价值的错误信息&#xff0c;显示在页面 手动注入 1. 寻找sql注入点 get注入 ?idxx url后加测试是否存在注入漏洞&#xff0c;报错则存在 post注入 把参数封装…...

使用 A2A Python SDK 实现 CurrencyAgent

谷歌官方的a2a-python SDK最近频繁的更新,我们的教程也需要跟着更新,这篇文章,我们通过 a2a-python sdk的 0.2.3 版本,实现一个简单的CurrencyAgent。 https://a2aprotocol.ai/blog/a2a-sdk-currency-agent-tutorial-zh 目录 源码准备详细过程 创建项目创建虚拟环境添加依…...

qt浏览文件支持惯性

#include <QApplication> #include <QListWidget> #include <QScroller> #include <QScrollerProperties>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建列表控件并添加示例项QListWidget listWidget;for (int i 0; i <…...

Python类的力量:第六篇:设计模式——Python面向对象编程的“架构蓝图”

文章目录 前言&#xff1a;从“代码堆砌”到“模式复用”的思维跃迁 一、创建型模式&#xff1a;对象创建的“智能工厂”1. 单例模式&#xff08;Singleton&#xff09;&#xff1a;全局唯一的“资源管家”2. 工厂模式&#xff08;Factory&#xff09;&#xff1a;对象创建的“…...

[实战]用户系统-2-完善登录和校验以及VIP

这里写目录标题 完善登录和校验新建lib-auth创建配置引入配置和JWT完善登录基本登录单点登录多点登录校验和拦截编写守卫编写装饰器使用完善VIP修改mysql模型编写vip守卫代码进度完善登录和校验 之前我们模拟过用户的登录,本节将实现token的生成,校验,redis做黑名单。我们需…...

负载均衡笔记

并发数—同时服务的调用方的数量 吞吐量—单位时间内&#xff0c;能接受和返回的数据请求量 TPS。 Transaction事务 QPS。Query 请求/查询 优化点&#xff1a; 减少并发数—防止并非过高 低级—限流—可用的用户少了&#xff1f;&#xff01; 多开几个口—分流 DNS 解析域…...

印度语言指令驱动的无人机导航!UAV-VLN:端到端视觉语言导航助力无人机自主飞行

作者&#xff1a;Pranav Saxena, Nishant Raghuvanshi and Neena Goveas单位&#xff1a;比尔拉理工学院&#xff08;戈瓦校区&#xff09;论文标题&#xff1a;UAV-VLN: End-to-End Vision Language guided Navigation for UAVs论文链接&#xff1a;https://arxiv.org/pdf/250…...