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

【JVM】类加载器 Bootstrap、Extension、Application、User Define 以及 双亲委派

以下环境为 jdk1.8

两大类

分类成员语言继承关系
引导类加载器bootstrap 引导类加载器C/C++
自定义类加载器extension 拓展类加载器、application 系统/应用类加载器、user define 用户自定义类加载器Java继承于 java.lang.ClassLoader

四小类

Bootstrap 引导类加载器

负责加载以下路径中 jar 包里的类
public class BootstrapClassLoader {public static void main(String[] args) {URL[] urls = Launcher.getBootstrapClassPath().getURLs();for (URL url : urls) {System.out.println(url.toExternalForm());}}
}

Extension 扩张类加载器

由 Bootstrap 加载,并将 Bootstrap 指定为 Extension 的父加载器

负责加载以下路径中 jar 包里的类
public class ExtensionClassLoader {public static void main(String[] args) {for (String path : System.getProperty("java.ext.dirs").split(";")) {System.out.println(path);}}
}

Extension 还可以加载开发者放入 java.ext.dirs 中 jar 包里的类

Application/System 应用/系统类加载器

由 Bootstrap 加载,并将 Extension 指定为 Application 的父加载器

负责加载以下路径中 jar 包里的类

用户自己开发的类的 classpath,如 com.example.demo.XXXClass

package com.chen.main;public class MyMain {}

这个由用户创建的 com.chen.main.MyMain 类,就会由 Application 加载

为什么是由 Application 加载呢?这是因为类加载器的双亲委派(按下不表)

User Define 用户自定义类加载器

由 Application 加载,并将 Application 指定为 User Define 的父加载器

为什么要有 User Define 用户自定义加载器

我们写了这么久代码好像也没有使用过用户自定义类加载器啊,使用上面三种类加载器好像完全足够了。但是当有以下几种需求时,就需要使用用户自定义加载器来实现了:

  • 隔离加载类

隔离 应用服务 与 框架 与 中间件 直接类的加载,防止可能存在相同路径的类发生冲突

  • 修改类加载的方式

可以不使用 Extension 和 Application,让用户自定义类加载器在我们需要的时间点,加载我们所需的类

  • 扩展加载源

.class 文件一般以本地、网络、压缩包(zip、jar、war)等方式加载

而用户自定义类加载器可以自己扩展加载源,比如在数据库、文件(jsp)、加密文件、各种电子设备中加载 .class 文件

  • 防止源码泄露

我们写的 Java 程序生成的 .class 字节码文件很容易被反编译出源码。因此为了防止源码泄露,就需要给字节码加密,但是加密后的字节码就无法被 JVM 提供的类加载器加载了,需要我们自己实现能够加载加密字节码的类加载器

负责加载用户指定路径的类

双亲委派

什么是双亲,其实就是 parent 家长的意思,因此也可以理解为 "家长委派模式"

前面提到了 Extension 的父加载器是 Bootstrap、Application 的父加载器是 Extension,但是父加载器并不是父类的意思,他们中间不存在继承关系

所谓 "父加载器" 只是 ClassLoader 类中的一个属性,这个属性正是 parent

而 Extension 与 Application 都继承于 ClassLoader,因此都有这个属性

类加载流程

向上委派

当要一个类加载器要加载类的时候

  • 当前的类加载器没有加载过该类

会先将加载任务提交给父加载器(即委派给双亲)。如果父加载器也有父加载器,那么加载任务会继续提交给父父加载器,直到没有父类加载器为止(即 parent 为 null),但是 parent 为 null 并不代表没有父类加载器,而是表示该加载器的父加载器为 Bootstrap 引导类加载器(因为 Bootstrap 是用 C/C++ 写的,并不是一个 Java 对象,无法存入 parent 属性中)。也就是说,最终的加载任务都会给到 Bootstrap 引导类加载器

  • 当前的类加载器已经加载过该类

直接结束(最初加载器)/  告知子加载器 "加载完成"(非最初加载器)

向下委派

Bootstrap

  • 该类在 Bootstrap 类加载器负责的加载路径下

Bootstrap 完成该类的加载任务,并告知将任务委派给他的子加载器 "我搞定了"(完成该任务)

  • 该类不在 Bootstrap 类加载器负责的加载路径下

Bootstrap 无法完成该类的加载任务,只能通知子加载器 "我搞不定,你自己试试看",将任务退回给子加载器(拒绝该任务)

子加载器

  • 该类在子加载器负责的加载路径下

子加载器完成该类的加载任务,并告知将任务委派给他的子子加载器 "我搞定了"(完成该任务)

  • 该类不在子加载器负责的加载路径下

子加载器无法完成该类的加载任务,只能通知子子加载器 "我搞不定,你自己试试看",将任务退回给子子加载器(拒绝该任务)

最初加载器

当最初加载器的所有祖宗都拒绝了最初加载器向上委派的类加载任务,它就只能自己来尝试加载了

  • 该类在最初加载器负责的加载路径下

最初加载器完成该类的加载任务

  • 该类不在子加载器负责的加载路径下

最初加载器无法完成该类的加载任务,由于它已经没有可以再向下委派的子加载器了,最终只能抛出 ClassNotFound 异常(在所有可加载的路径下,找不到这个类)

作用

避免重复加载类

比如 A 类和 B 类都有一个父类 C 类,那么当 A 启动时就会将 C 类加载起来,那么在 B 类进行加载时就不需要在重复加载 C 类了

确保程序安全性

使用双亲委派模型可以保证了 Java 的核心 API 不被篡改,如果没有使用双亲委派模型,而是每个类加载器自己加载就会出现一些问题。比如我们自己编写一个名为 java.lang.Object 类,那么程序运行的时候,AppClassLoader 就会加载这个 Object 类,如果我们写的 Object 类有问题,那么所有继承于 Object 类的类就会全部出错,整个程序直接崩溃 down 掉
 

http://www.lryc.cn/news/229973.html

相关文章:

  • 读书笔记:彼得·德鲁克《认识管理》第15章 使工作富有成效:工作和过程
  • 媒体软文投放的流程与媒体平台的选择
  • 【excel技巧】如何取消excel隐藏?
  • AIGC专栏8——EasyPhoto 视频领域拓展-让AIGC肖像动起来
  • C++ RBTree 理论
  • 制作这种在线宣传画册,可轻松收获客户!
  • 数据结构 | 图
  • [文件读取]shopxo 文件读取(CNVD-2021-15822)
  • zookeeper应用之分布式锁
  • 20. 机器学习——PCA 与 LDA
  • 深度学习准召
  • AtCoder ABC154
  • 可以非常明显地感受到,一场有关直播带货的暗流正在涌动
  • C++中的四种构造函数
  • 通过反射获取某个对象属性是否存在,并获取对象值
  • 【MySQL】存储过程与函数
  • 【数学】Pair of Topics—CF1324D
  • Qt文档阅读笔记-Fetch More Example解析
  • QtC++与QTableView详解
  • HG/T 6002-2022 氟树脂粉末涂料检测
  • 【java】idea可以连接但看不到database相关的files
  • 信驰达科技加入车联网联盟(CCC),推进数字钥匙发展与应用
  • p9 Eureka-搭建eureka服务
  • 阶段七-Day01-SpringMVC
  • Python---集合中的交集 、并集 | 与差集 - 特性
  • C++调用lua脚本,包括全局函数绑定、类绑定,十分钟快速掌握
  • 快乐数[简单]
  • Spring源码阅读-ClassPathXmlApplicationContext
  • 考研分享第2期 | 中央财经大学管理科学跨考北大软微金融科技406分经验分享
  • Linux安装java jdk配置环境 方便查询