java 类加载器

java 类加载器

参考博客

深入理解Java类加载器: https://www.cnblogs.com/cl-rr/p/9081817.html
深入理解Java类加载器(ClassLoader): https://blog.csdn.net/javazejian/article/details/73413292
高级开发必须理解的Java中SPI机制:https://www.jianshu.com/p/46b42f7f593c
深入分析Java反射-类实例化和类加载 https://cloud.tencent.com/developer/article/1650015

java 类加载机制的层次结构

前置:每一个编写的.java扩展名文件通过java编译器扩展成.class文件,保存着java代码转换后的虚拟机指令

  1. 类加载过程: 加载-> 验证 -> 准备 -> 解析 -> 初始化
    • 加载:通过类的完全限定查找此类字节码文件,通过字节码船舰一个class对象
    • 验证:目的在于确保当前的信息符合当前虚拟机要求,不会威胁虚拟机自身安全
      • 文件格式验证
      • 元数据验证
      • 字节码验证
      • 符号引用验证
    • 准备: 为类变量分配内存并且设置初始值(0,false…),fianl修饰的会在编译的时候直接赋值常量.
    • 解析: 主要将常量池中的符号引用替换成直接引用的过程.
    • 初始化: 类加载的最后阶段,先初始化父类然后初始化子类, 执行静态初始化器和静态初始化成员变量

java中的类加载器

  • 启动(Bootstrap)类加载器BootstrapClassLoader:JVM自身需要的类,使用C++语言实现的,是虚拟机的一部分.将java/lib路径下的核心类库的jar包或者-Xbbotclasspath参数指定的路径下的jar包加载到内存中
  • 扩展(Extension)类加载器ExtClassLoader:java语言实现,负责加载java/lib/ext目录下或者-Djava.ext.dir指定位路径中的类库.重写的是URLClassLoader类中的findClass方法,遵循了双亲委托机制
  • 系统(System)类加载器AppClassLoader:负责加载系统类路径java -classpath 或者-D java.class.path 指定路径下的类库,开发者可以直接使用系统类加载器,ClassLoader.getSystemClassLoader(),重写的URLClassLoader类中的loadClass方法,没有遵循双亲委托机制
  • 用户自定义类加载器

类加载器关键方法

  • loadClass(String) 加载指定包名的二进制类,不建议用户重写但是可以直接调用本方法
    • 使用了双亲委派机制,先调用夫加载器的loadClass,假如加载失败再调用自己的loadClass方法
  • findClass(String) 在调用父类的loadClass失败后,会调用findClass方法,自定义类加载器的时候建议将自定义的类加载逻辑重写在这。
  • defineClass(Byte b, int off, int len) byte字节流解析成JVM能够识别的Class对象
    • 在自定义类加载器时,会直接覆盖ClassLoader的findClass()方法并编写加载规则,取得要加载类的字节码后转换成流,然后调用defineClass()方法生成类的Class对象
    • 如果直接调用defineClass()方法生成类的Class对象,这个类的Class对象并没有解析(也可以理解为链接阶段,毕竟解析是链接的最后一步),其解析操作需要等待初始化阶段进行。
  • resolveClass(Class≺?≻ c) 使用该方法可以使用类的Class对象创建完成也同时被解析。前面我们说链接阶段主要是对字节码进行验证,为类变量分配内存并设置初始值同时将字节码文件中的符号引用转换为直接引用。

双亲委派机制

除了顶层的启动类加载器外,其余的类加载器应当都有自己的父类加载器(父子关系并非通常所说的类继承关系,而是采用组合关系复用父类加载器的相关代码)
在这里插入图片描述

优势: 由顶层加载器依次尝试加载,无法加载时使用子加载器,层级关系使得避免类的重复加载,
在这里插入图片描述

  • loadClass(String) 加载指定位置的二进制类型

缺点:双亲委托机制当中如果存在相同的接口实现(如:JDBC,JCE,JNDI,JAXP,JBI)SPI的接口是Java核心库的一部分,是由启动类加载器(Bootstrap Classloader)来加载的;SPI的实现类是由系统类加载器(System ClassLoader)来加载的。引导类加载器是无法找到 SPI 的实现类的,因为依照双亲委派模型,BootstrapClassloader无法委派AppClassLoader来加载类。

双亲委托机制的破坏(线程上下文类加载器TCCL)

  • java.util.ServiceLoader

显式加载&隐式加载

  • 显式加载: 代码中通过调用ClassLoader加载Class对象
    • Class.forName()
    • this.getClass().getClassLoader().loadClass()
  • 隐式加载: 不直接在代码中调用ClassLoader方法加载class对象通过虚拟机自动加载到内存中.

编写自己的类加载器

为什么要编写自己的类加载器?

  • 当class文件不在ClassPath路径下时,默认加载器无法找到该class文件.
  • 当class文件通过网络传输可能会加密的时候,需要先解密后再加载到jvm中
  • 当需要热部署的时候(一个class文件通过不同的类加载器产生不同的class对象)

自定义的类加载器相关问题

1. 自定义类加载器加载出来的类无法由Object类型转化成想要的类型

原因:只要由不同的加载器加载出来的对象的类都不是同一个类,强转会使用AppClassLoader类型进行类的强转,由于加载器的不同,所以无法强转,会报ClassNotCasException

2.类多次加载导致的内存溢出问题
在这里插入图片描述

扩展

使用类加载器实现热加载

  • 什么是热加载?
    • 热加载是指在不重启系统的情况下当字节码发生改变了之后能够替换该Class创建的对象。
  • 如何实现热加载?
    • 创建一个守护进程,检查class文件是否被修改过
    • 使用自定义的classLoader来加载类,得到新的class对象
    • 再由新的class对象来创建实例,实现动态更新
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值