转载自 自定义ClassLoader和双亲委派机制

ClassLoader

ClassLoad:类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。

双亲委派机制

某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

自己对JVM中的ClassLoader和双亲委派机制的一些理解:

  • java虚拟机中的class其实都是通过classloader来装载的
  • 只有当你使用该class的时候才会去装载,一个classloader只会装载同一个class一次。
  • 不同的类加载器的实例所加载的字节码文件,其通过反射获取的对象不是相同类型(相互赋值会抛出类型强转异常)。即:判断两个类是否为同一对象的标准里面有一条是类加载器必须为相同。
  • 双亲委派机制能在很大程度上防止内存中出现多个相同的字节码文件。
  • 在加载类的时候默认会使用当前类的ClassLoader进行加载(类A中引用了类B,JVM会用类A的类加载器加载类B)。
  • 在线程中加载一个类的时候:当前线程的类加载器可以通过Thread类的getContextClassLoader()获得,也可以通过setContextClassLoader()自己设置类加载器(PS:自己没有试验过)。

ClassLoader体系结构图

ClassLoader体系结构图


package com.tzx.reflection;public class MyClassLoader {public static void main(String[] args) {// TODO Auto-generated method stubSystem.out.println(Thread.currentThread().getContextClassLoader());System.out.println(ClassLoaderTest.class.getClassLoader());System.out.println(System.class.getClassLoader());System.out.println(ClassLoader.getSystemClassLoader());System.out.println(ClassLoader.getSystemClassLoader().getParent());System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());}}

运行结果:


sun.misc.Launcher$AppClassLoader@4aa298b7
sun.misc.Launcher$AppClassLoader@4aa298b7
null
sun.misc.Launcher$AppClassLoader@382f3bf0
sun.misc.Launcher$ExtClassLoader@25082661
null

按照双亲委派机制加载类,每当需要加载一个新的类时,当前的类加载器会先委托其父加载器,查询有没有加载该类。如果父类加载器已近加载该类,那么直接返回加载的class对象,如果没有那么继续向上寻找父类加载器,如果在祖宗类加载器Bootstrap都没有加载该类,那么需要当前的类加载器自己加载,如果当前的类加载器也不能加载则会跑出ClassNotFoundException异常 (PS:类加载器没有向下寻找,没有getChild只有getParent)。

用这种思想去解析上边代码:Thread.currentThread().getContextClassLoader()指出当前的类加载器是AppClassLoader,需要加载MyClassLoader.class先在父类加载器(ExtClassLoader)中寻找,没有再向祖宗类加载中寻找(Bootstrap ClassLoader),还没有找到那么AppClassLoader自己去加载。

JVM中的类加载器类型:

  • (Bootstrap ClassLoader)启动类加载器:
    负责加载java_home/jar/lib/rt.jar目录下的核心类或- Xbootclasspath指定目录下的类。由于引导类加载器全部是native代码来实现的并且涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作,从上面的ClassLoader体系结构图中可以看出在java代码中获取启动类加载器为null。

rt.jar.png

像System.java这样的由系统提供的类都在rt.jar中,由Bootstrap ClassLoader加载,由于Bootstrap类加载器不是Java写的,所以打印出来的类名为null。

  • (Extension)扩展类加载器:负责加载java_home/lib/ext目录下的扩展类或 -Djava.ext.dirs 指定目录下的类。 开发者可以直接使用标准扩展类加载器。

我们将第一段代码生产的MyClassLoader.class文件打包成jar(java打包成jar|执行jar包中的main方法),放在java_home/jar/lib/ext目录下。

ext.png

再次执行该java程序


im@58user:/usr/lib/jvm/jdk1.8.0_101/jre/lib/ext$ java -cp MyClassLoader.jar com.loadclass.demo.ClassLoaderTest start
sun.misc.Launcher$AppClassLoader@55f96302
sun.misc.Launcher$ExtClassLoader@70dea4e
null
sun.misc.Launcher$AppClassLoader@55f96302
sun.misc.Launcher$ExtClassLoader@70dea4e
null

通过终端输出结果我们可以看到执行ClassLoaderTest程序的类加载器是AppClassLoader,但加载ClassLoaderTest类的类加载器是ExtClassLoader。因为java_home/jar/lib/ext/.jar在执行程序之前就被ExtClassLoader类加载器加载过了。这样避免了类的重复加载~!~!*

  • (System)类加载器:负责加载-classpath/-Djava.class.path所指的目录下的类。开发者可以直接使用标准扩展类加载器。一般来说,Java应用的类都是由他来完成加载的。
    除了以上三种类型的类加载器,还有一个中比较特殊的:线程上下文类加载器(PS:暂时没做这方面的记录)。

自定义类加载器

  • 定义

package com.tzx.reflection;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;public class MyClassLoader extends ClassLoader{static {System.out.println("MyClassLoader");}public static final String driver = "/home/im/Desktop/";public static final String fileTyep = ".class";public Class findClass(String name) {byte[] data = loadClassData(name);return defineClass(data, 0, data.length);}public byte[] loadClassData(String name) {FileInputStream fis = null;byte[] data = null;try {File file = new File(driver + name + fileTyep);System.out.println(file.getAbsolutePath());fis = new FileInputStream(file);ByteArrayOutputStream baos = new ByteArrayOutputStream();int ch = 0;while ((ch = fis.read()) != -1) {baos.write(ch);}data = baos.toByteArray();} catch (IOException e) {e.printStackTrace();System.out.println("loadClassData-IOException");}return data;}
}
  • 使用

public class ClassLoaderTest {public static void main(String[] args) {MyClassLoader cl1 = new MyClassLoader();//磁盘中/home/im/Desktop/Hello.class文件存在try {Class c1 = cl1.loadClass("Hello");Object object = c1.newInstance();} catch (ClassNotFoundException e) {e.printStackTrace();System.out.println("main-ClassNotFoundException");} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}}
}

自定义ClassLoader和双亲委派机制相关推荐

  1. jvm面试 -- 谈谈ClassLoader ,ClassLoader的双亲委派机制 , loadClass和forName的区别

    谈谈ClassLoader ? ClassLoader的双亲委派机制 ? loadClass和forName的区别 ?

  2. java安全沙箱(一)之ClassLoader双亲委派机制

    java是一种类型安全的语言,它有四类称为安全沙箱机制的安全机制来保证语言的安全性,这四类安全沙箱分别是: 类加载体系 .class文件检验器 内置于Java虚拟机(及语言)的安全特性 安全管理器及J ...

  3. java类加载-ClassLoader双亲委派机制

    "类加载体系"及ClassLoader双亲委派机制.java程序中的 .java文件编译完会生成 .class文件,而 .class文件就是通过被称为类加载器的ClassLoade ...

  4. JVM-白话聊一聊JVM类加载和双亲委派机制源码解析

    文章目录 Java 执行代码的大致流程 类加载loadClass的步骤 类加载器和双亲委派机制 sun.misc.Launcher源码解析 Launcher实例化 Launcher 构造函数 双亲委派 ...

  5. JVM入门(位置、体系结构、类加载器、双亲委派机制、沙箱安全机制、Native、PC寄存器、方法区、堆(新生区{伊甸园区、幸存区}、养老区、永久区)、OOM、GC算法、JMM)

    目录 一.JVM的位置 二.JVM的体系结构 三.类加载器 1.类加载器举例 2. JVM中提供了三层的ClassLoader 3. 双亲委派机制(重要) 3.1 工作原理 3.2.优点 四.沙箱安全 ...

  6. 浅谈JVM(一) ClassLoader的双亲委派和沙箱机制

    转载自 https://blog.csdn.net/start_lie/article/details/79016312 JVM(Java Virtual Machine)   java虚拟机 JVM ...

  7. 违反ClassLoader双亲委派机制三部曲第二部——Tomcat类加载机制

    转载自 违反ClassLoader双亲委派机制三部曲第二部--Tomcat类加载机制 前言: 本文是基于 ClassLoader双亲委派机制源码分析 了解过正统JDK类加载机制及其实现原理的基础上,进 ...

  8. 类加载机制、双亲委派机制深度解析以及如何自定义类加载器

    文章目录 1.类加载运行的全过程 2. JVM类加载器的初始化 3.双亲委派机制 4.编写自定义类加载器 5.(Tomcat)如何打破双亲委派机制 当我们运行一个类的时候,首先要通过类加载机制把类加载 ...

  9. 深入类加载器-类加载器作用,类缓存、类加载器的层次结构、ClassLoader类介绍、代理模式之双亲委派机制

    1.类加载器的作用 类加载器的作用是将class字节码文件加载到内存中,并将这些静态数据转化为方法区中的运行时数据结构,同时在堆中生成代表这个类的java.lang.Class对象,作为访问方法区中数 ...

最新文章

  1. 华为三层交换机路由配置案例_{华为HCNP-RS}三层交换机的配置实例
  2. 7个相同小球4个不同盒子_【计算启蒙】4个游戏陪娃玩懂“数拆分”,加减法都不用愁!...
  3. “约见”面试官系列之常见面试题第十篇值meta标签(建议收藏)
  4. C#中IDisposable 回收非托管资源
  5. 错过SaaS,就是错过这个时代
  6. 18个C/C++的基本知识点,带好小本子记录一下
  7. GoogLeNet的心路历程(一)
  8. Spring Data Rest如何暴露ID字段
  9. JAVA格式化输出浮点数:空格,位数
  10. Android源码下载编译(高通)
  11. 某热门单击手游lua解密.md
  12. 这篇文章,自带背景音乐。因为它来自1993年!
  13. 基于STM32设计的数字电子秤
  14. python爬虫 | 同步刷新网页爬取实例 | 小白篇
  15. 机器学习的入门“秘籍”
  16. 银行电话营销数据分析
  17. 硕士论文结构分析与如何写作
  18. java万能爬虫爬取拉勾网
  19. java开发工具对比_Eclipse和STS哪个好_Java开发工具优缺点对比一览
  20. 个性代码注释 大合集

热门文章

  1. 幂等问题 vs 如何判断是否是4的幂
  2. 网络计算机室电源线怎么布,网吧综合布线(电源和网络)经验谈
  3. [JavaWeb-JavaScript]JavaScript特殊语法
  4. [Java基础]字符缓冲流
  5. 奔小康赚大钱 HDU - 2255( 二分图匹配KM算法详解)
  6. 连续不等_第九讲 函数的连续性与函数的间断点
  7. 内存超频trfc_这只是开始?四款DDR4内存超频效果对比
  8. word List35
  9. Java HashMap的实现原理详解
  10. CF436F Banners(分块/凸包/单调队列)