郑州有哪些搞网站开发的公司,电商财务内账做账流程,去百度建网站,网络设计及网络设计文档我们写的 Java 代码是以 .java 结尾的#xff0c;编译后变成 .class 字节码文件。 JVM 想要运行程序#xff0c;就必须把这些 .class 文件搬进内存里。 负责搬运的搬运工#xff0c;就叫 类加载器 (ClassLoader)。 但在 JVM 的世界里#xff0c;搬运工不是一个人#xff0…我们写的 Java 代码是以.java结尾的编译后变成.class字节码文件。JVM 想要运行程序就必须把这些.class文件搬进内存里。负责搬运的搬运工就叫类加载器 (ClassLoader)。但在 JVM 的世界里搬运工不是一个人而是一个有着严格等级森严的“家族”。‍ 一、技术分析什么是“双亲委派”“双亲委派”这个翻译其实有点糟糕它英文叫Parent Delegation Model更准确的翻译应该是“父辈委派模型”。1. 家族族谱JVM 里有三个核心的类加载器它们构成了“爷爷-爸爸-儿子”的层级关系爷爷启动类加载器 (Bootstrap ClassLoader)最高层C 编写。它只负责加载 Java 最核心的类比如java.lang.String、java.util.List存放在JAVA_HOME/lib目录下。爸爸扩展类加载器 (Extension ClassLoader)负责加载一些扩展的系统类存放在JAVA_HOME/lib/ext目录下。儿子应用程序类加载器 (Application ClassLoader)底层搬砖的。负责加载你自己写的业务代码以及 Maven 引入的第三方 jar 包你的 ClassPath。2. 核心机制“有事找长辈”当“儿子”收到一个加载类比如User.class的请求时它的运作机制是极其“懒惰”和“尊老”的儿子不干活儿子先把任务扔给爸爸。爸爸不干活爸爸再把任务扔给爷爷。爷爷尝试干活爷爷一看这不在我的核心库管辖范围内干不了打回给爸爸。爸爸尝试干活爸爸一看也不在扩展库里干不了打回给儿子。儿子自己干儿子苦逼地去 ClassPath 里找到了User.class自己加载了。一句话总结任何类的加载都要先往上层层甩锅直到顶层上面实在干不了再一层层踢皮球踢回来自己动手。️ 二、有什么用为什么要设计得这么麻烦Java 官方费尽心机搞这一套“拼爹”机制主要为了两个字安全。1. 防止核心 API 被篡改 (沙箱安全机制)假设有个黑客或者不懂事的初学者在自己的项目里写了一个类packagejava.lang;publicclassString{// 里面植入了清空硬盘的病毒代码}如果没有双亲委派机制“儿子”加载器直接把这个带毒的String类加载进内存整个系统就崩溃了。有了双亲委派加载java.lang.String时请求层层上交到了“爷爷”Bootstrap。“爷爷”一看java.lang.String这我熟啊我核心库里有于是“爷爷”直接加载了官方正版的String类。黑客自己写的那个冒牌String类永远得不到被加载的机会。2. 避免类的重复加载Java 判断两个类是否相等的条件是类名相同 加载它的 ClassLoader 相同。如果“儿子”和“爸爸”各自加载了一遍同一个类内存里就会出现两个长得一样却互相不认识的类会导致严重的类型转换异常ClassCastException。双亲委派保证了越基础的类越由上层统一加载保证了全局唯一性。⚔️ 三、为什么要破坏它怎么破坏的既然双亲委派这么好为什么还要破坏它因为这个模型有一个致命的缺陷长辈看不见晚辈的代码。爷爷只能加载lib目录它绝对加载不到你写在业务里的类。这在某些特定场景下引发了巨大的灾难。场景一JDBC 的 SPI 机制困境 (基础类要调用用户类)问题所在JDBC 的核心接口java.sql.DriverManager是 Java 官方提供的基础类由爷爷 (Bootstrap)加载。但是真正的数据库驱动比如 MySQL 驱动com.mysql.cj.jdbc.Driver是各家厂商写的第三方包放在用户的 ClassPath 下只有儿子 (Application)能看见。当DriverManager想要去初始化 MySQL 驱动时“爷爷”是根本找不到这个驱动类的爷爷也不能使唤儿子委派只能向上不能向下。死局如何破坏 (怎么解决)Java 引入了线程上下文类加载器 (Thread Context ClassLoader, TCCL)。“爷爷”在加载时偷偷去当前线程的口袋里把“儿子”加载器掏了出来用“儿子”加载器去加载了 MySQL 驱动。这本质上是长辈逆向委派晚辈干活打破了双亲委派向上的规则。场景二Tomcat 的应用隔离困境 (同名类的多版本共存)问题所在假设你在同一个 Tomcat 里部署了两个 Web 项目App1 和 App2。App1 用的是Spring 4.0App2 用的是Spring 5.0。如果 Tomcat 遵守双亲委派App1 启动时“儿子”加载了Spring 4.0。App2 启动时想加载Spring 5.0“儿子”一看哎我已经加载过 Spring 的类了直接用缓存吧结果就是App2 强行使用了 Spring 4.0当场报错崩溃。如何破坏 (怎么解决)Tomcat 选择“造反”。它自定义了WebAppClassLoader。当 Tomcat 加载你的 Web 应用代码时它的逻辑变成了先自己找在当前应用的/WEB-INF/classes和/WEB-INF/lib下找。找到就加载直接跳过了问爸爸的步骤。自己找不到再去委派给爸爸。这样一来每个 Web 应用都有自己专属的 ClassLoaderApp1 和 App2 互相隔离完美实现了多版本框架的共存。 四、总结规则就是用来打破的双亲委派 (向上委派)为了保证基础类库的安全性和唯一性防篡改。破坏双亲委派 (向下或平级委派)为了解决基础类需要调用业务代码SPI/JDBC或者实现代码的物理隔离和热部署Tomcat/OSGi。