JVM深入原理(六)(二):双亲委派机制

简介: 自定义类加载器打破双亲委派机制的方法:复写ClassLoader中的loadClass方法常见问题:要加载的类名如果是以java.开头,则会抛出安全性异常加载自定义的类都会有一个共同的父类Object,需要在代码中交由父类加载器去加载自定义类加载器不手动指定parent会默认指定应用类加载两个自定义类加载器加载同一个类会被认为是两个对象,只有相同的类加载器+想通的类限定名才会被认为是一个对象。

JVM系列文章

  1. 深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器_eden used total max-CSDN博客
  2. JVM深入原理(一+二):JVM概述和JVM功能-CSDN博客
  3. JVM深入原理(三+四):JVM组成和JVM字节码文件-CSDN博客
  4. JVM深入原理(五):JVM组成和JVM字节码文件-CSDN博客
  5. JVM深入原理(六)(一):JVM类加载器-CSDN博客
  6. JVM深入原理(六)(二):双亲委派机制-CSDN博客
  7. JVM深入原理(七)(一):运行时数据区-CSDN博客
  8. JVM深入原理(七)(二):运行时数据区-CSDN博客
  9. JVM深入原理(八)(一):垃圾回收-CSDN博客
  10. JVM深入原理(八)(二):垃圾回收-CSDN博客

目录

6.5. 类加载器-双亲委派机制

6.5.1. 双亲委派机制-作用

6.5.2. 双亲委派机制-工作流程

6.5.3. 双亲委派机制-父加载器

6.5.4. 双亲委派机制-面试题

6.5.5. 双亲委派机制-代码主动加载一个类

6.6. 类加载器-打破双亲委派机制

6.6.1. 打破委派-ClassLoader原理

6.6.2. 打破委派-打破的场景

6.6.3. 打破委派-自定义类加载器

6.6.4. 打破委派-线程上下文类加载器

6.6.5. 打破委派-OSGi模块化

6.7. 类加载器-JDK8前后的类加载器


6.5. 类加载器-双亲委派机制

6.5.1. 双亲委派机制-作用

  • 双亲委派机制的作用:解决谁来加载类的问题
  1. 保证类加载的安全性:避免恶意代码替换JDK中的核心类库(比如:java.lang.String),确保核心类库的完整性和安全性
  2. 避免类的重复加载:避免一个类被反复加载

6.5.2. 双亲委派机制-工作流程

  • 双亲委派机制的工作流程:当类加载器接收到加载类的任务时,会自底向上查找父类加载器是否加载过该类,是则结束这个过程,否则自顶向下进行加载该类

    image.gif 编辑
  • 自底向上工作流程:每个类加载器都有父类加载器,在类加载过程中,每个类加载器会检查自身是否加载了该类,是则直接返回该类,否则将加载请求委派给父类加载器
  • 自底向上工作优点:只要一个类加载器加载过该类就会直接返回,避免了重复加载
  • 自顶向下工作流程:父类加载器会检查当前类是否在自己的加载目录中,是则加载后返回类对象,否则交给子类去加载
  • 自顶向下的优点:实现从上到下的加载优先级

6.5.3. 双亲委派机制-父加载器

  • 父加载器辨析:每个Java实现的类加载器中保存了一个成员变量叫"父"(parent)类加载器,可以理解为它的上级,但不是继承关系

    image.gif 编辑
  • 应用程序类加载器的父类加载器:扩展类加载器
  • 扩展类加载器的父类加载器:null,启动类加载器是JVM源码中的,Java代码是获取不到的,但是代码逻辑上启动类加载器的父类加载器还是启动类加载器
  • 启动类加载器的父类加载器:启动类加载器是用C++编写的没有父类加载器

6.5.4. 双亲委派机制-面试题



  • image.gif 编辑
  • 启动类加载器加载,根据双亲委派机制,它的优先级是最高的


  • image.gif 编辑
  • 不能,因为启动类加载器在程序启动时已经加载了JDK提供的String类,接收到委派请求时会直接返回加载好的String类

6.5.5. 双亲委派机制-代码主动加载一个类

  • 使用Java代码可以主动加载一个类,有两种实现方式:
  1. 调用Class.forName方法使当前类的类加载器去加载该类
  2. 调用getClassLoader方法获取当前类的类加载器,再用类加载器的loadClass方法让该类加载器加载指定的方法

6.6. 类加载器-打破双亲委派机制

6.6.1. 打破委派-ClassLoader原理

  • ClassLoader的原理就存在于四个核心方法中

    image.gif 编辑
  1. loadClass:
  • 作用:类加载的入口,内部实现双亲委派机制,内部会调用findClass
  • 代码逻辑:
  1. 使用synchronized加锁,防止多线程情况下出现类被多次加载
  2. 使用findLoadClass方法判断这个类是否被当前类加载器加载过

    image.gif 编辑
  1. 未被加载过,则判断父类加载器是否为空
  1. 不为空,则由父类加载器再判断是否加载过这个类,依次类推
  2. 为空,则由启动类加载器去加载
  1. 已被加载过,则直接返回这个类
  1. 执行完向上委派动作,但类任未被加载,则由当前类加载器加载
  1. 使用URLClassLoader的findClass方法获取特定目录下的Class字节码文件,获取文件对象
  1. 调用重载方法传入resolve=false,不执行连接的过程
  1. findClass:由类加载器子类实现,获取二进制数据时调用defineClass,比如URLClassLoader会根据文件路径去获取类文件的二进制数据
  2. defineClass:对类名进行校验,调用JVM方法将字节码信息加载到JVM运行时数据区
  3. resolveClass:执行类生命周期中的连接阶段

6.6.2. 打破委派-打破的场景

  • Tomcat打破双亲委派机制的原因:Tomcat程序中运行多个Web应用时,如果Web应用中出现相同限定名的类,Tomcat要保证这些类能够正常加载并运行且保证他们是不同的类,Tomcat就需要打破双亲委派机制

    image.gif 编辑
  • Tomcat打破双亲委派机制的方式:Tomcat为每一个Web应用提供了自定义类加载器来加载对应的类,这样就实现了应用之间的类的隔离

    image.gif 编辑

6.6.3. 打破委派-自定义类加载器

  • 自定义类加载器打破双亲委派机制的方法:复写ClassLoader中的loadClass方法
  • 常见问题:
  • 要加载的类名如果是以java.开头,则会抛出安全性异常
  • 加载自定义的类都会有一个共同

    image.gif 编辑 的父类Object,需要在代码中交由父类加载器去加载

    image.gif 编辑
  • 自定义类加载器不手动指定parent会默认指定应用类加载
  • 两个自定义类加载器加载同一个类会被认为是两个对象,只有相同的类加载器+想通的类限定名才会被认为是一个对象

6.6.4. 打破委派-线程上下文类加载器

  • 线程上下文类加载器应用场景:JDBC(为例),JNDI
  • JDBC概述:JDBC提供DriverManager来管理jar包中引入的数据库驱动,这样就能在Java中操作不同的数据库
  • JDBC打破委派困境:DriverManager位于rt.jar包中,由启动类加载器加载,但依赖中的MySQL驱动实现类需要应用类加载器去加载

    image.gif 编辑
  • JDBC-SPI机制:SPI(Service Provider Interface)JDK内置服务发现机制,通过SPI快速找到Driver接口的实现类,类似Spring中的依赖注入
  • JDBC工作原理:MySQL为例

    image.gif 编辑
  1. 启动类加载器加载位于rt.jar包的DriverManager
  2. 初始化DriverManager时,通过SPI机制加载jar包中的数据库驱动实现类,将此实现类注册到DriverManager中交由他管理
  • DriverManager利用SPI机制会去加载META-INF/services路径下的java.sql.Driver文件,将MySQL实现了Driver接口的驱动实现类的全限定名写入文件就可以被加载并管理
  1. SPI中利用了线程上下文类加载器(一般是应用类加载器)去加载获取的Driver驱动类并创建对象

    image.gif 编辑
  • DriverManager使用ServiceLoader去加载Driver实现类,ServiceLoader中获取线程上下文类加载器去加载实现类
  1. 这种由启动类加载器加载的类去委派应用程序类加载器去加载类的方式打破了双亲委派机制
  2. 但是JDBC案例中都使用的是JDK提供的类加载器还是会走双亲委派流程,并没有重写loadClass,也可以说没有打破双亲委派机制

6.6.5. 打破委派-OSGi模块化

  • OSGi作用:OSGi是模块化框架,解决早起JDK所有核心类都放在rt.包下难以管理的问题,它实现同级之间的类加载器委托加载.还使用类加载器实现了热部署功能

    image.gif 编辑

6.7. 类加载器-JDK8前后的类加载器

  • JDK8之前版本:扩展类加载器和应用程序类加载器的源码都位于rt.jar包下的sun.misc.Launcher.java中,这两个加载器都实现了URLClassLoader,也可以说JDK8之前类加载器是按照类的位置去加载的

    image.gif 编辑
  • JDK8之后版本:JDK9引入了module概念,类不在放在jar包中加载,而是放在一个个jmod文件中,从jmod文件中加载文件,类加载器发生很多变化:

    image.gif 编辑
  1. 启动类加载器由Java编写,位于jdk.internal.loader.ClassLoader类中

    image.gif 编辑
  1. Java中的BootClassLoader继承自BuiltinClassLoader实现从模块中找到要加载的字节码文件
  2. 启动类加载器依然无法通过Java代码找到保持了统一
  1. 扩展类加载器被替换成了平台类加载器(Platform Class Loader)

    image.gif 编辑
  1. 平台类加载器遵循模块化方式加载字节码文件,继承关系从URLClassLoader变为BuiltinClassLoader,BuiltinClassLoader实现了从模块中加载字节码文件,平台类加载器的存在更多是为老板的设计方案兼容,自己没有特殊逻辑
目录
相关文章
|
25天前
|
Oracle Java 关系型数据库
JVM深入原理(一+二):JVM概述和JVM功能
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行。
52 0
|
25天前
|
Arthas 存储 Java
JVM深入原理(三+四):JVM组成和JVM字节码文件
目录3. JVM组成3.1. 组成-运行时数据区3.2. 组成-类加载器3.3. 组成-执行引擎3.4. 组成-本地接口4. JVM字节码文件4.1. 字节码文件-组成4.1.1. 组成-基础信息4.1.1.1. 基础信息-魔数4.1.1.2. 基础信息-主副版本号4.1.2. 组成-常量池4.1.3. 组成-方法4.1.3.1. 方法-工作流程4.1.4. 组成-字段4.1.5. 组成-属性4.2. 字节码文件-查看工具4.2.1. javap4.2.2. jclasslib4.2.3. 阿里Arthas
35 0
|
25天前
|
存储 安全 Java
JVM深入原理(五):JVM组成和JVM字节码文件
类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析。
26 0
|
25天前
|
Arthas Java 测试技术
JVM深入原理(六)(一):JVM类加载器
目录6. JVM类加载器6.1. 类加载器-概述6.2. 类加载器-执行流程6.3. 类加载器-分类(JDK8)6.3.1. JVM底层实现的类加载器6.3.1.1. 启动类加载器6.3.2. Java代码实现类的加载器6.3.2.1. 扩展类加载器6.3.2.2. 应用程序类加载器6.4. 类加载器-Arthas查看类加载器
28 0
|
25天前
|
存储 安全 Java
JVM深入原理(七)(一):运行时数据区
栈的介绍:Java虚拟机栈采用栈的数据结构来管理方法调用中的基本数据,先进后出,每一个方法的调用使用一个栈帧来保存栈的组成:栈:一个线程运行所需要的内存空间,一个栈由多个栈帧组成栈帧:一个方法运行所需要的内存空间活动栈帧:一个线程中只能有一个活动栈帧栈的生命周期:栈随着线程的创建而创建,而回收会在线程销毁时进行栈的执行流程:栈帧压入栈内执行方法执行完毕释放内存若方法间存在调用,那么会压入被调用方法入栈,执行完后释放内存,再执行当前方法,直到执行完毕,释放所有内存。
28 0
|
25天前
|
存储 缓存 安全
JVM深入原理(七)(二):运行时数据区
堆的作用:存放对象的内存空间,它是空间最大的一块内存区域.栈上的局部变量表中,可以存放堆上对象的引用。静态变量也可以存放堆对象的引用,通过静态变量就可以实现对象在线程之间共享。堆的特点:线程共享:堆中的对象都需要考虑线程安全的问题垃圾回收:堆有垃圾回收机制,不再引用的对象就会被回收方法区的概述:方法区是存放基础信息的位置,线程共享,主要包括:类的元信息:保存了所有类的基本信息运行时常量池:保存了字节码文件中的常量池内容静态常量池:字节码文件通过编号查表的方式找到常量。
28 0
|
25天前
|
缓存 算法 Java
JVM深入原理(八)(一):垃圾回收
弱引用-作用:JVM中使用WeakReference对象来实现软引用,一般在ThreadLocal中,当进行垃圾回收时,被弱引用对象引用的对象就直接被回收.软引用-作用:JVM中使用SoftReference对象来实现软引用,一般在缓存中使用,当程序内存不足时,被引用的对象就会被回收.强引用-作用:可达性算法描述的根对象引用普通对象的引用,指的就是强引用,只要有这层关系存在,被引用的对象就会不被垃圾回收。引用计数法-缺点:如果两个对象循环引用,而又没有其他的对象来引用它们,这样就造成垃圾堆积。
48 0
|
25天前
|
算法 Java 对象存储
JVM深入原理(八)(二):垃圾回收
Java垃圾回收过程会通过单独的GC线程来完成,但是不管使用哪一种GC算法,都会有部分阶段需要停止所有的用户线程。这个过程被称之为StopTheWorld简称STW,如果STW时间过长则会影响用户的使用。一般来说,堆内存越大,最大STW就越长,想减少最大STW,就会减少吞吐量,不同的GC算法适用于不同的场景。分代回收算法将整个堆中的区域划分为新生代和老年代。--超过新生代大小的大对象会直接晋升到老年代。
39 0
|
3月前
|
缓存 算法 Java
JVM实战—4.JVM垃圾回收器的原理和调优
本文详细探讨了JVM垃圾回收机制,包括新生代ParNew和老年代CMS垃圾回收器的工作原理与优化方法。内容涵盖ParNew的多线程特性、默认线程数设置及适用场景,CMS的四个阶段(初始标记、并发标记、重新标记、并发清理)及其性能分析,以及如何通过合理分配内存区域、调整参数(如-XX:SurvivorRatio、-XX:MaxTenuringThreshold等)来优化垃圾回收。此外,还结合电商大促案例,分析了系统高峰期的内存使用模型,并总结了YGC和FGC的触发条件与优化策略。最后,针对常见问题进行了汇总解答,强调了基于系统运行模型进行JVM参数调优的重要性。
153 10
JVM实战—4.JVM垃圾回收器的原理和调优
|
3月前
|
消息中间件 Java 应用服务中间件
JVM实战—1.Java代码的运行原理
本文介绍了Java代码的运行机制、JVM类加载机制、JVM内存区域及其作用、垃圾回收机制,并汇总了一些常见问题。
JVM实战—1.Java代码的运行原理