理解和运用 ClassLoader 该篇文章就够了
定义
根据《深入理解Java虚拟机》提到“通过一个类的全限定名(packageName.ClassName)来获取描述此类的二进制字节(class文件字节)这个动作的代码模块就叫做类加载器(ClassLoader)”。
作用
1、通常类加载器的作用是加载资源(字节码文件)到java虚拟机中,想要在一个jvm 进程中唯一确认一个类,除了类的全限定名外,还需要指定它是由哪个类加载器加载的。
2、比如我们的类库需要通过远程网络获取,可以通过自定义类加载器从远程加载字节码文件。
3、java的字节码文件很容易反编译出来,一些核心的代码不想被反编译出来,可以对字节码进行加密,然后通过自定义的类加载器加载这些字节码,然后进行解码返回给虚拟机。
4、比如jvm的热加载和热部署等功能也需要自定义类加载器来完成。
.......
java类加载器的种类
1、Bootstrap ClassLoader : 该加载器是最顶层的类加载器,它是加载放在{Java_home}\lib目录 或者-Xbootclasspath指定路径下类库。
2、Extension ClassLoader : 该类加载器负载加载{Java_home}/lib\ext目录 或者System.getenv("java.ext.dirs")系统变量路径下的类库。
3、Application ClassLoader : 该类加载器加载用户程序类路径下的类库,它是默认的程序的类加载器。
双亲委派机制
1、双亲委派机制,双亲委派除了启动类加载器(Bootstrap ClassLoader)外,其他的类加载器都应该有自己父加载器。它们的实现不是通过继承来实现的,而是通过组合的方式。当加载某个Class时,当前类加载器会把这个加载请求委派给其父类加载器加载,同理父类加载器同样委派其它的父类加载器加载,直到无其父类类加载器加载为止,如果父类加载器加载失败,才会由其子类加载。
2、使用双亲委派机制,有个明显的特征是:Java类随着它的类加载器一起具备了一种优先级的层次关系。比如rt.jar包中的java.lang.Object,由于它所在位置是由启动类加载器加载,所以Object类在程序的各种类加载器环境中都是同一个类。
3、双亲委派模型如下:

ClassLoader
可以看下ClassLoader 双亲委派模型的大致代码框架如下:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 1、查看该类是否加载
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
// 2、如果未加载,委托给父类加载器加载
if (parent != null) {
c = parent.loadClass(name, false);
} else {
//3、没有父类加载器,委托给BootstrapClassLoader
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// 父类加载器没有加载到,则自己加载
long t1 = System.nanoTime();
c = findClass(name);
// 记录该类加载的状态Stat.
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
// resolve :true,需要对类进行链接(链接阶段包括:准备,解析,初始化类)
if (resolve) {
resolveClass(c);
}
return c;
}
}
1、通过以上可以知道,我们可以继承ClassLoader 来实现自己的类加载器,然后重写findClass()方法,这些还是保存了双亲委派机制。
2、当我们重写findClass()方法时,得到该类的字节码后,需要调用defineClass()来放回Class<?>对象。
URLClassLoader
1、一般自定义的类加载器可以直接继承该类,该类加载器通过添加url路径来获取类。
2、可以在其构造函数上URLClassLoader(URL[] urls, ClassLoader parent)直接进行添加其URL。
3、也可以通过addURL(URL)添加其URL。
自定义类加载器
1、首先假设main-project为我们自己编写的工程,其依赖某一api:service-spi。而service-spi的实现有很多,project-spi-impl是其中的一个。
2、当main-project仅依赖service-spi,而project-spi-impl不在工程的类加载路径下。所以需要自定义类加载器,从某个路径下的jar加载进来。CoreClassLoader就是自定义的类加载器。
3、CoreClassLoader继承自URLClassLoader,然后把相关搜索路径添加到该类加载器即可。
4.github:https://github.com/zhvqee/class-loader
SpringBoot 对类加载器的运用
1、SpringBoot 工程通过spring-boot-maven-plugin插件打包。把相关资源和依赖包都打到一个jar包中(all in one)。其包的结构如下:

BOOT-INF/classes:存放的是本工程的class文件
BOOT-INF/lib:存放的是本工程依赖的二方包和三方包。
META-INF/MANIFEST.MF:该文件记录了程序启动入口等。
o.s.b.loader包下就是springboot自定义的类加载器。
2、当我们执行java -jar xxxx 时,会读取MANIFEST.MF下
Main-Class: org.springframework.boot.loader.JarLauncher,
该配置就是程序的路口。而我们编写的Main方法不是真正的启动的入口。
3、当执行Launcher#launch()方法时,会把SpringBoot自定义的类加载器LaunchedURLClassLoader设置线程的上下文中,并通过该自定义类加载器加载我们自己编写的main方法所在的类,然后利用反射调用main方法。代码片段如下:
Class<?> mainClass = Thread.currentThread().getContextClassLoader().loadClass(this.mainClassName);
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
mainMethod.invoke(null, new Object[] { this.args });
4、LaunchedURLClassLoader 类加载器继承URLClassLoader类加载器,它加载的路径就是可执行jar下BOOT-INF下的class文件和二方包、三方包。
Class.forName() 和 ClassLoader.load()
1、JVM 加载的类主要经过以下几个步骤:加载,链接,初始化,试用,卸载。
2、Class.forName()默认是需要对加载的类进行初始化。
3、ClassLoader.load实际调用的是ClassLoader.load(className,false),false:表示不进行链接,不进行链接也就代表不会进行初始化的操作,类的静态块和静态对象都不会执行。
该文章
理解和运用 ClassLoader 该篇文章就够了的更多相关文章
- Vue开发入门看这篇文章就够了
摘要: 很多值得了解的细节. 原文:Vue开发看这篇文章就够了 作者:Random Fundebug经授权转载,版权归原作者所有. 介绍 Vue 中文网 Vue github Vue.js 是一套构建 ...
- 还不会Traefik?看这篇文章就够了!
文章转载自:https://mp.weixin.qq.com/s/ImZG0XANFOYsk9InOjQPVA 提到Traefik,有些人可能并不熟悉,但是提到Nginx,应该都耳熟能详. 暂且我们把 ...
- 想让安卓app不再卡顿?看这篇文章就够了
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由likunhuang发表于云+社区专栏 实现背景 应用的使用流畅度,是衡量用户体验的重要标准之一.Android 由于机型配置和系统的 ...
- Python正则表达式,看完这篇文章就够了...#华为云·寻找黑马程序员#【华为云技术分享】
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...
- 数据可视化之PowerQuery篇(四)二维表转一维表,看这篇文章就够了
https://zhuanlan.zhihu.com/p/69187094 数据分析的源数据应该是规范的,而规范的其中一个标准就是数据源应该是一维表,它会让之后的数据分析工作变得简单高效. 在之前的文 ...
- 想理解JVM看了这篇文章,就知道了!
前言 本章节属于Java进阶系列,前面关于设计模式讲解完了,有兴趣的童鞋可以翻看之前的博文,后面会讲解JVM的优化,整个系列会完整的讲解整个java体系与生态相关的中间件知识.本次将对jvm有更深 ...
- 想理解JVM看了这篇文章,就知道了!(一)
前言 本章节属于Java进阶系列,前面关于设计模式讲解完了,有兴趣的童鞋可以翻看之前的博文,后面会讲解JVM的优化,整个系列会完整的讲解整个java体系与生态相关的中间件知识.本次将对jvm有更深 ...
- Java进阶专题(十一) 想理解JVM看了这篇文章,就知道了!(中)
前言 上次讲解了JVM内存相关知识,今天继续JVM专题. JVM垃圾回收算法 什么是垃圾回收 程序的运行必然需要申请内存资源,无效的对象资源如果不及时处理就会一直占有内存资源,最终将导致内存溢 ...
- Kafka面试,看这篇文章就够了
原文链接:https://mp.weixin.qq.com/s/zxPz_aFEMrshApZQ727h4g** 引言 MQ(消息队列)是跨进程通信的方式之一,可理解为异步rpc,上游系统对调用结果的 ...
随机推荐
- Android Studio连接手机调试教程已决解
Android Studio连接手机调试教程 Windows电脑连接安卓手机需要下载安装驱动,确保电脑联上网络. 准备条件: 1.电脑上安装应用宝软件. 2.手机开发者选项里面打开USB调试,USB安 ...
- Beta冲刺——汇总随笔
一.代码规范与计划随笔 Beta冲刺--代码规范与计划 二.凡事预则立随笔 Beta冲刺--凡事预则立 三.10篇冲刺随笔 Beta冲刺--第一天 Beta冲刺--第二天 Beta冲刺--第三天 Be ...
- hadoop目录结构
Hadoop目录结构 重要目录结构: bin目录:存放对Hadoop相关服务(HDFS,YARN)进行操作的脚本 etc目录:Hadoop的配置文件目录,存放Hadoop的配置文件 lib目录:存放H ...
- STP、PVST、MST协议
• STP:生成树协议 ○ 阻止环形链路的广播风暴 • PVST:VLAN生成树 ○ 是STP的进阶版不仅能阻止广播风暴,还可以做到基于VLAN进行流量均衡. ...
- LInux维护一:VirtualMachine磁盘扩容
- SpringBoot 集成Shiro之使用Redis缓存授权认证信息
因为用户认证与授权需要从数据库中查询并验证信息,但是对于权限很少改变的情况,这样不断从数据库中查询角色验证权限,对整个系统的开销很大,对数据库压力也随之增大.因此可以将用户认证和授权信息都缓存起来,第 ...
- unixbench性能测试跑分工具
UnixBench是一个类unix系(Unix,BSD,Linux)统下的性能测试工具,一个开源工具,被广泛用与测试linux系统主机的性能 所谓跑分工具,不仅各项的测试有得分,最后跑完也会有一个综合 ...
- ps ww
[root@ma ~]# ps ww -p 1 PID TTY STAT TIME COMMAND 1 ? Ss 0:01 /sbin/init[root@ma ~]# ps -p 1 PID TTY ...
- 【Web】HTML入门小结
文章目录 HTML? HTML 初识元素/标签 HTML语义化标签 标题 段落 font HTMl链接 HTML图像 HTML列表 HTML div HTML 块级元素与行内元素 HTML常用带格式作 ...
- [oracle] exp-00091
产生原因: 在数据库的服务器端和客户端字符集不同的情况下,导出(dump)数据库表时,会产生这个错误.虽然产生这个错误,但好像对导入没有影响. 解决办法: 查看服务器端字符集: 打开SQLPLUS,执 ...