c 自定义实现string类 clear_有关类加载器的总结
对于java开发来说,classLoader往往是容易被我们忽视的一个重要知识点。而classLoader对java的发展也有很大的影响。例如。
- 早期的applet应用,通过网络远程加载class文件。
- web容器对应用class文件的加载。
- spi机制的支持。
- 等等。
学习知识往往带着疑问去学习,效果可能会比较好。接下来我带着几个问题来解答classLoader有关的疑问。
- 什么是classLoader?为什么需要classLoader?
- 什么是双亲委派? 为什么需要双亲委派?
- 什么是contextClassLoader? 为什么需要ContextClassLoader?
- classLoader用于什么场景?什么情况下需要什么classLoader?
接下来就一一解答上面的疑问。以我的学习方式来说,对这块知识点用反证的思维来理解比较简单。
分析classLoader之前,我们先直接class的加载过程,并且下面方法跟加载过程一一对应。
- 加载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是不会导致类的初始化的
有疑惑点的地方,再详情说说。
- 整个加载过程,都是锁住的,确保指定对当前类的全限定名加载一个线程在执行。
- 如果自定义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_有关类加载器的总结相关推荐
- c 自定义实现string类 clear_基于scala2.13实现自定义的集合类 (下)
前缀映射 作为第三个示例,您将学习如何将一种新型的可变地图集成到集合框架中. 这个想法是通过 "Patricia trie"实现以String作为键类型的可变映射. 实际上,术语P ...
- java中的类加载器有,Java自定义的类加载器,java自定义加载,在java中类加载器有以...
Java自定义的类加载器,java自定义加载,在java中类加载器有以 在java中类加载器有以下几种java虚拟机自带的加载器 1)根类加载器(Bootstrap,c++实现)2)扩展类加载器(Ex ...
- Java class类文件和类加载器详解以及代码优化
JVM就是Java虚拟机,它是Java程序运行的载体. 计算机只识别0和1.Java是⾼级语⾔.⾼级语⾔编写的程序要想被计算机执⾏,需要变成⼆进制形式的本地机器码.能直接变成机器码的语义是C++,它的 ...
- 深入类加载器-类加载器作用,类缓存、类加载器的层次结构、ClassLoader类介绍、代理模式之双亲委派机制
1.类加载器的作用 类加载器的作用是将class字节码文件加载到内存中,并将这些静态数据转化为方法区中的运行时数据结构,同时在堆中生成代表这个类的java.lang.Class对象,作为访问方法区中数 ...
- 引导类、扩展类、系统类加载器的使用及演示
一.启动类加载器(引导类加载器, Bootstrap ClassLoader) 1.这个类是使用c/c++语言实现的, 嵌套在JVM内部. 2.它用来加载java的核心库(java_home/jre/ ...
- 022-JVM-各类加载器加载哪些类?(类加载器的势力范围)
上一篇:021-JVM-双亲委派机制 https://yuhongliang.blog.csdn.net/article/details/111565510 上篇说到各类加载器再第二次得到加载一个类的 ...
- java applet找不到类_java – Applet类加载器在applet的jar中找不到类
我开始问这个问题,然后在提交之前找出答案.我决定发布这个问题,以便遇到同样问题的其他人能够从我的错误中吸取教训. 我遇到了一个applet(实际上是JApplet)无法实例化另一个类的问题,该类与ap ...
- c 自定义实现string类 clear_CC++语言15|类的继承和派生实现代码重用、扩充
在C++中,继承是一个对象自动获取其父对象的所有属性和行为的过程.通过继承,您可以重用,扩展或修改在其他类中定义的属性和行为.通过继承,可以实现函数重写以及多态. 在C++中,继承另一个类的成员的类称 ...
- thinkphp3.2.3 调用自定义模型提示找不到类_面试BAT必问的JVM,今天我们来说一说它类加载器的底层原理...
类加载器的关系 类加载器的分类 JVM支持两种类加载器,一种为引导类加载器(Bootstrap ClassLoader),另外一种是自定义类加载器(User Defined ClassLoader) ...
最新文章
- linux 输出重定向
- tensorboard出现OSError: [Errno 22] Invalid argument问题解决
- 对CSS了解-overflow:hidden
- python奖励多少钱_关于python的问题,好的高奖励!
- linux无桌面重做系统,Linux不需要重做系统
- UPS不间断电源的种类有哪些 常见的3类UPS电源
- mac php 403,mac下配置apache以及403问题
- 计算机室 多媒体教室制度,专用教室、多媒体教室管理制度
- 苹果Mac怎样切换大写输入法?
- 谈如何整定PID参数
- 解决win10新建文本文档内容可以打开但显示图标不对的问题
- 【AD】原理图放置差分对,报错Missing Negative Net for differential pair
- Impala Shell 和 Impala SQL
- 英语会话必须掌握的五种基本结构[转]
- 如何通俗理解并快速写出麦克斯韦方程组?
- Bert—SST-2
- 报错 -Uncaught ReferenceError: axios is not defined
- html实现文本的查找与替换,在 InDesign 中查找并替换文本
- 工厂废品小爱同学mini的重生(3)——— Uboot和硬改SD卡
- 安装冰点还原后无法更改系统时间怎么办
热门文章
- 它来了,它来了,最强目标检测算法YOLO v4,它真的来了!!!
- NLP、CV、ML全覆盖,这份私藏论文清单你一定要看看
- modis数据介绍_【更新90篇】地理数据科学技术文章合集,欢迎大家点赞、在看、转发三连!...
- 【虚拟化】docker部署nginx
- 进程和线程的定义和区别
- 前端传数据到后台部分接收成功,部分接收失败
- 牛客题霸 NC11 将升序数组转化为平衡二叉搜索树
- Visual C++——Visual C++ 6.0 转 Visual Studio[Visual C++]编译错误[错误	D8016	“/ZI”和“/Gy-”命令行选项不兼容]解决方案
- JAVA——关闭ServerSocket
- 最长不下降子序列问题