首页 > 其他 > 详细

类加载机制2——类加载器

时间:2021-05-29 08:55:53      阅读:38      评论:0      收藏:0      [点我收藏+]

前置知识

1、什么是类加载器?

类加载器是通过类的全限定名,来获取类的二进制字节流的代码。

类加载机制:JVM把Class数据加载到内存,并对数据进行验证、准备、解析、初始化,最终形成可以被虚拟机使用的Java类。

类的默认加载器,通过双亲委派机制进行类的加载。

2、类的唯一性确定

加载类的加载器和类本身一起确定类的唯一性,若同一个Class文件,被不同的加载器加载,则是不同的类。

 


双亲委派机制

1、三层类加载器

           技术分享图片

2、各层加载器的职责

  1. 启动类加载器:主要负责加载java的核心类库,/lib目录下的rt.jar、resources.jar、charsets.jar和class等
  2. 扩展类加载器:主要负责加载java扩展包中的类库,/lib/ext 目录下的jar包和class文件
  3. 应用类加载器:主要负责加载当前应用的classpath下的所有类
  4. 自定义加载器:加载指定路径的class文件

3、双亲委派机制

  当一个加载器收到加载一个类的请求时,会先把该请求委派给自己的父类加载器执行加载,故所有的类加载都会被委派到启动类加载器中,若父类加载器加载失败,才会自己尝试加载。

4、双亲委派机制的实现

  在ClassLoader类中的loadClass方法中实现

  技术分享图片

  以上源代码的逻辑为:

  1. 先检查类是否已经加载过
  2. 若类还未加载,则检查父类加载器是否存在,若存在,则调用父类加载器的loadClass方法进行加载;若不存在,则用启动加载器加载。
  3. 若父类加载器加载失败,则尝试自己加载,调用自己的加载方法findClass

5、为什么要双亲委派?好处是什么?

  1. 使类跟类加载器一样拥有更严格的层级关系。如Object类,无论在哪里使用,最终都会被委派给启动类加载器加载,保证Object类在程序的各种类加载器环境中,都是同一个类。
  2. 如果没有使用双亲委派模型,可以由各个类加载器自行加载的话,如果用户自定义了一个名为java.lang.Object类,放在程序的Classpath中,那系统中就会出现多个不同的Object类,导致应用程序执行的混乱。

6、不同层级的类加载器之间是组合关系,不是继承关系

  通过构造器注入parent

  技术分享图片

7、如何主动破坏双亲委派机制?

  自定义一个类加载器,继承抽象类ClassLoader,重写loadClass方法,使其不进行双亲委派。

8、loadClass、findClass、defineClass区别

  1. loadClass:默认实现的双亲委派机制
  2. findClass:加载类class字节码,是当前类加载器的加载方法,若想自定义的类加载器也遵守双亲委派机制,则只需要重写findClass方法
  3. defineClass:将类的字节码转换成Class对象

9、破坏双亲委派机制的三个事件

   1、第1次是JDK1.2之前,那时已经有了类加载器和ClassLoader类,但是不是双亲委派机制的

   2、第2次是模型自身的缺陷导致的,双亲委派机制使得越基础的类越由上层的加载器进行加载,正常情况下,用户代码继承、调用基础类,双亲委派机制加载没有问题。但是若从基础类中调回用户代码,则在上层加载器中,是无法找到下层的应用代码的,此时就需要破坏双亲委派机制,Java中由基础类调用SPI接口的地方都会如此。

   SPI接口:Service Provider Interface,如JNDI、JDBC等。其本质是面向接口编程,具体实现或扩展由第三方在应用程序中实现。

   在上层类加载器中无法加载到应用程序中实现的具体类,如何解决这个问题?

   通过线程上下文类加载器实现ContextClassLoader。由Thread类的setContextClassLoader方法设置,若未设置,则会继承父线程的类加载器。在应用程序中,若没有设置过这个值,则默认为应用程序类加载器。

    技术分享图片

    因此,在调用SPI接口时,可以通过getContextClassLoader获取线程上下文加载器,通过应用程序加载器去加载所需的SPI服务类。这是一种父类加载器去请求子类加载器完成类加载的过程,破坏了双亲委派机制。如DriverManager中的实现

        技术分享图片

  3、第3次破坏双亲委派机制是为了追求程序的动态性,如代码的热替换,程序的热部署等,即代码替换或模块替换后,不需要重启即可生效。

    这种实现是基于自定义类加载器实现的,此时加载器不再是有上下层级的树状结构,而是一个网状结构,每一个模块都有一个自定义的加载器,每当要替换掉一个模块时,就会将模块和类加载器都一起替换掉,以实现代码的热替换。   

 


参考书籍:《深入理解Java虚拟机》第3版,作者:周志明

 

类加载机制2——类加载器

原文:https://www.cnblogs.com/a-candy/p/14824055.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!