对于java开发来说,classLoader往往是容易被我们忽视的一个重要知识点。而classLoader对java的发展也有很大的影响。例如。

  1. 早期的applet应用,通过网络远程加载class文件。
  2. web容器对应用class文件的加载。
  3. spi机制的支持。
  4. 等等。

学习知识往往带着疑问去学习,效果可能会比较好。接下来我带着几个问题来解答classLoader有关的疑问。

  1. 什么是classLoader?为什么需要classLoader?
  2. 什么是双亲委派? 为什么需要双亲委派?
  3. 什么是contextClassLoader? 为什么需要ContextClassLoader?
  4. classLoader用于什么场景?什么情况下需要什么classLoader?

接下来就一一解答上面的疑问。以我的学习方式来说,对这块知识点用反证的思维来理解比较简单。

分析classLoader之前,我们先直接class的加载过程,并且下面方法跟加载过程一一对应。

类加载过程 , copy from http://www.importnew.com/25295.html
  • 加载class文件,从jvm中对应的Class文件。
  • 接着验证Class是否合法。即对class进行有效性、合法性验证。
  • 准备阶段的工作:为类变量分配内存并初始化值,这里的初初始化值并不是设置用户指定的值。例如。

public static int age = 12;
public static String name = "wang007";
初始化值,先将int = 0; name = null;在接下来的初始化阶段, 再讲 int = 12, name = "wang007";

其他阶段可参考JVM 类加载机制详解 - ImportNew;

1. 什么是classLoader?为什么需要classLoader?

classLoader是用于加载我们编译好的class文件到jvm中。在ClassLoader这个类中能看到相关重要的方法。下面我就列举几个比较重要的方法来解释一下。

public 

loadClass方法,根据 java全限定名称 加载 很明显,该方法对应类加载过程的 加载阶段

findClass方法, 该方法是需要子类去实现的方法, 根据 java全限定名称 加载 class文件。 可以从本地文件系统加载, 也可以通过网络从任一服务器中加载。 对于需要自实现classLoader的话,一般只需要实现该方法即可。

resolveClass方法,根据loadClass方法加载好的Class对象, 进行连接工作。 即验证、准备、解析方法。

还有defineClass方法,将用byte[]二进制数组 创建class对象。final方法无法拓展,在findClass方法中,获取byte[],调用defineClass方法创建Class对象。


2 什么是双亲委派? 为什么需要双亲委派?

说到双亲委派模型,那么必须先介绍BootstrapClassLoader,ExtClassLoader,AppClassLoader.

  • BootstrapClassLoader负责加载rt.jar包中的class文件。 C++写的,所以在java不可见,用null引用代替。
  • ExtClassLoader负责加载ext目录的jar包中的class文件。
  • AppClassLoader负责加载classpath下的class文件,即我们编写的java文件编译成的class文件。

所谓的双亲委派模型是指加载class时, 先让父classLoader加载class,如果父classLoader加载不到,再自己加载。 这里的“父”, 不是指继承关系,而是指属性指定的“父”ClassLoader。

AppClassLoader的父加载器是ExtClassLoader,ExtClassLoader的父加载器是BootstrapClassLoader。

public 

在ClassLoader这个类中, 用parent属性指定当前classLoader的“父”加载器。 AppClassLoader,ExtClassLoader都是继承该类。

为什么需要双亲委派?

双亲委派模型是为了保证应用安全的,确保rt.jar包内的代码只由BootstrapClassLoader加载的。 例如我们在代码中用AppClassLoader(即SystemClassLoader)加载String.class,AppClassLoader会让ExtClassLoader加载的, ExtClassLoader会让BootClassLoader加载,因为String.class在rt.jar中,所以BootstrapClassLoader会加载成功, 返回到 ExtClassLoader, 最后返回到AppClassLoader中。

如果我们用自实现的ClassLoader加载String.class(这个String.class我加点后门代码),不通过双亲委派模型,直接自己加载。是可以加载出来的,但是跟BootstrapClassLoader加载出来的String不是同一个。因为ClassLoader不同, 加载出来的Class对象也不同。 如果让自定义ClassLoader加载出来的String 赋值给BootClassLoader,会报ClassCastException.

这里展示双亲委派的关键代码

//这里指定 resolve = false,所以ClassLoader加载class是不会导致类的初始化的

有疑惑点的地方,再详情说说。

  1. 整个加载过程,都是锁住的,确保指定对当前类的全限定名加载一个线程在执行。
  2. 如果自定义classLoader设置parent = null, 那么就会跳ext路径下类加载,可能会导致冲突。 所以自定义ClassLoader一般指定 parent = appClassLoader。

3. 什么是contextClassLoader? 为什么需要ContextClassLoader?

ContextClassLoader就是通过thread.getContextClassLoader()方法获取的ClassLoader。 我知道,如果我换做你,听到这种解释, 我都想锤死我自己。哈哈哈。

上面说的双亲委派模型, 看似天衣无缝,其实未必。我觉得ContextClassLoader恰恰是为双亲委派模型擦屁股的角色。

当我们需要加载一个Class的对象,从自定义ClassLoader,到appClassLoader,再到ExtClassLoader,最后到BootstrapClassLoader。没问题, 很顺利。这是从下到上加载。 但是反过来,当从上到下加载的时候,这个变得是一个不可能完成的任务。为了弥补这个缺陷, 特定设计的ContextClassLoader。

但可能又会有疑问了, 什么情况下, 会出现从上到下加载呢?

我举个很实用,但是又几乎用不到的例子吧(是不是像极了好吃又吃不饱的东西。233333) spi机制。 这里我就不展开讲spi了。有兴趣的话,自行搜索资料学习,基本大部分框架都会用到spi。

我们都知道,SUN是个一流的公司,因为一流的公司卖标准嘛, 虽然这个一流的公司已经死了。 在rt.jar包中, 定义了很多spi接口, JDBC,JNDI等等。 但是spi接口的实现一般都是以第三方jar的方式提供到classpath下。 例如, JDBC spi的接口由BootstrapClassLoader加载, 但是有些spi接口中会加载spi实现包的类,而BootstrapClassLoader只能加载rt.jar的类, 不能classPath下的类,所以通过thread.getContextClassLoader方法获取到ClassLoader(这个一般是AppClassLoader)。然后通过这个classLoader在spi 接口中加载其实现。

补充一个知识点。如果类A引用类B,且类B还未加载, 那么用加载类A的类加载器加载类B。

我找了下,只找到了DriverManger这个类下,通过spi机制加载Driver实现。(例如mysql driver)只不过这个用的是ClassLoader.getSystemClassLoader()方法, 效果跟contextClassLoader差不多。都是为了加载第三方实现类。

public 

接下来来看下。ContextClassLoader是怎么来的。

public 

在Launcher的构造方法中,获取ExtClassLoader,如果是第一次调用,就会创建一个ExtClassLoader。 获取再获取AppClassLoader。第一次调用, 也会创建一个。 最后将appClassLoader设置到Thread。

我们知道,main方法是java程序的入口,而main方法所在的类也是有AppClassLoader加载的。 而AppClassLoader正在来自于Launcher类,所以在Launcher类在main方法运行之前就创建好了。

为啥AppClassLoader也叫SystemClassLoader呢? 因为:

public 

在ClassLoader类中的getSystemClassLoader方法,就是从launcher类中获取的appClassLoader,并设置到ClassLoader类的静态属性中。 所以AppClassLoader也叫SystemClassLoader

ContextClassLoader的传播。

//thread的构造方法中调用init方法

在新建一个线程的时候,就是会把原来线程所在的ClassLoader设置到新的线程中。 就这么一直传播下去。 如果我们改变当前线程的ContextClassLoader,那么当前线程上新建Thread的ContextClassLoader就是改变后的。

例如。

public 

所以ContextClassLoader的传播是通过新建Thread的时候,把当前线程的ContextClassLoader设置到新线程中。

同时还有类似方式传播的东西。inheritableThreadLocals。 也叫可继承的ThreadLocal。有兴趣的话,可以自行查找资料。InheritableThreadLocal。跟ThreadLocal差不多的作用。

4. ClassLoader的运用场景。

其实ClassLoader,我们直接或间接的用了很多。例如Tomcat需要加载项目中的class文件。 按照默认提供的ClassLoader是不够的。必须自定义ClassLoader来加载项目中的class文件。还有热启动机制,想必也是用到了自定义ClassLoader。

最后再解决一个疑问点。 Class.forName与ClassLoader.loadClass 的区别?

前面介绍了ClassLoader的loadClass方法,是不会触发类的初始化操作的。

而Class.forName是会触发类的初始化操作。

public 

在forName0方法中,第一个参数就是类名,第二个参数是是否初始化类, 第三个参数是指定ClassLoader。 所以在forName方法中, 指定了需要初始化, 还指定了ClassLoader为当前调用类的ClassLoader。

其实Class.forName还有一个重载方法,可以指定是否初始化,和ClassLoader

public 

好了,有关classLoader的知识就总结到这里了。 有些点由于篇幅关系就没有深入下去了。

c 自定义实现string类 clear_有关类加载器的总结相关推荐

  1. c 自定义实现string类 clear_基于scala2.13实现自定义的集合类 (下)

    前缀映射 作为第三个示例,您将学习如何将一种新型的可变地图集成到集合框架中. 这个想法是通过 "Patricia trie"实现以String作为键类型的可变映射. 实际上,术语P ...

  2. java中的类加载器有,Java自定义的类加载器,java自定义加载,在java中类加载器有以...

    Java自定义的类加载器,java自定义加载,在java中类加载器有以 在java中类加载器有以下几种java虚拟机自带的加载器 1)根类加载器(Bootstrap,c++实现)2)扩展类加载器(Ex ...

  3. Java class类文件和类加载器详解以及代码优化

    JVM就是Java虚拟机,它是Java程序运行的载体. 计算机只识别0和1.Java是⾼级语⾔.⾼级语⾔编写的程序要想被计算机执⾏,需要变成⼆进制形式的本地机器码.能直接变成机器码的语义是C++,它的 ...

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

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

  5. 引导类、扩展类、系统类加载器的使用及演示

    一.启动类加载器(引导类加载器, Bootstrap ClassLoader) 1.这个类是使用c/c++语言实现的, 嵌套在JVM内部. 2.它用来加载java的核心库(java_home/jre/ ...

  6. 022-JVM-各类加载器加载哪些类?(类加载器的势力范围)

    上一篇:021-JVM-双亲委派机制 https://yuhongliang.blog.csdn.net/article/details/111565510 上篇说到各类加载器再第二次得到加载一个类的 ...

  7. java applet找不到类_java – Applet类加载器在applet的jar中找不到类

    我开始问这个问题,然后在提交之前找出答案.我决定发布这个问题,以便遇到同样问题的其他人能够从我的错误中吸取教训. 我遇到了一个applet(实际上是JApplet)无法实例化另一个类的问题,该类与ap ...

  8. c 自定义实现string类 clear_CC++语言15|类的继承和派生实现代码重用、扩充

    在C++中,继承是一个对象自动获取其父对象的所有属性和行为的过程.通过继承,您可以重用,扩展或修改在其他类中定义的属性和行为.通过继承,可以实现函数重写以及多态. 在C++中,继承另一个类的成员的类称 ...

  9. thinkphp3.2.3 调用自定义模型提示找不到类_面试BAT必问的JVM,今天我们来说一说它类加载器的底层原理...

    类加载器的关系 类加载器的分类 JVM支持两种类加载器,一种为引导类加载器(Bootstrap ClassLoader),另外一种是自定义类加载器(User Defined ClassLoader) ...

最新文章

  1. linux 输出重定向
  2. tensorboard出现OSError: [Errno 22] Invalid argument问题解决
  3. 对CSS了解-overflow:hidden
  4. python奖励多少钱_关于python的问题,好的高奖励!
  5. linux无桌面重做系统,Linux不需要重做系统
  6. UPS不间断电源的种类有哪些 常见的3类UPS电源
  7. mac php 403,mac下配置apache以及403问题
  8. 计算机室 多媒体教室制度,专用教室、多媒体教室管理制度
  9. 苹果Mac怎样切换大写输入法?
  10. 谈如何整定PID参数
  11. 解决win10新建文本文档内容可以打开但显示图标不对的问题
  12. 【AD】原理图放置差分对,报错Missing Negative Net for differential pair
  13. Impala Shell 和 Impala SQL
  14. 英语会话必须掌握的五种基本结构[转]
  15. 如何通俗理解并快速写出麦克斯韦方程组?
  16. Bert—SST-2
  17. 报错 -Uncaught ReferenceError: axios is not defined
  18. html实现文本的查找与替换,在 InDesign 中查找并替换文本
  19. 工厂废品小爱同学mini的重生(3)——— Uboot和硬改SD卡
  20. 安装冰点还原后无法更改系统时间怎么办

热门文章

  1. 它来了,它来了,最强目标检测算法YOLO v4,它真的来了!!!
  2. NLP、CV、ML全覆盖,这份私藏论文清单你一定要看看
  3. modis数据介绍_【更新90篇】地理数据科学技术文章合集,欢迎大家点赞、在看、转发三连!...
  4. 【虚拟化】docker部署nginx
  5. 进程和线程的定义和区别
  6. 前端传数据到后台部分接收成功,部分接收失败
  7. 牛客题霸 NC11 将升序数组转化为平衡二叉搜索树
  8. Visual C++——Visual C++ 6.0 转 Visual Studio[Visual C++]编译错误[错误 D8016 “/ZI”和“/Gy-”命令行选项不兼容]解决方案
  9. JAVA——关闭ServerSocket
  10. 最长不下降子序列问题