本文转载自微信公众号《程序员阿兴》,作者程序员阿兴。转载本文,请联系程序员阿星公众号。大家好,我是头发还很多的阿星。今天的主角是“日常开发中存在感极低的类加载器”,那你一定要先认识老大,阿星会为你介绍类加载器(本文不涉及源码)。什么是类加载器我们平时写了那么多Java代码,却不知道Java类的加载过程。是不是很尴尬,为了打破尴尬,阿星不得不从Java类入手。我们写的Java类是.java文件,由Java编译器编译成.class文件,.class文件存放Java代码转换后的虚拟机指令。当程序使用Java类时,JVM虚拟机将其.class文件加载到虚拟机的内存中,由类加载器负责加载。类加载过程其实类加载器就和日常生活中坐地铁过安检一样。如果你不相信我,请看下图。安检要经过一系列的检查。如果感冒了,不能携带威胁人身安全的物品。同样的类加载还要经过一系列的检查过程,称为类加载过程。类加载过程分为加载、验证、准备、解析和初始化。下图是对类加载过程的简单介绍。类加载过程不是本文的重点。如果你对这方面感兴趣,可以自己去百度或者谷歌。先说这篇文章的要点吧。双亲委托模型的威力有点像骗子。JVM虚拟机提供了三种加载器,分别是启动类加载器(Bootstrap)、扩展类加载器(Extension)和系统类加载器(System)。每个类加载器都有明确的加载范围:Bootstrap:加载/lib路径下的核心类库扩展类加载器(Extension):加载/lib/extl路径下的系统类加载器(System):加载系统类路径classpath,也就是我们经常使用的classpath路径。一般来说,类加载器是程序中默认的类加载器。双亲委托模式的原理也很简单。类加载器收到类加载请求,会委托给父类加载器执行,父类加载器还有它的父类加载器,然后进一步向上委托,递归,直到顶层类加载器,如果顶层级类加载器加载类,成功返回类对象,否则委托给下级类加载器执行,依次递归(这里的父子关系不是通常所说的继承关系,而是使用组合关系实现的)。说白了,每个儿子都很懒,有事就交给父亲去做。直到他爸爸说我不行,儿子才会想办法自己完成。双亲委托模式是为了避免双重加载和核心类篡改。特殊需求在日常开发中,我们可能会有特殊的业务需求,可能需要使用自定义的类加载器。加载器的上级必须是系统类加载器。你想要的有特殊需求的资源隔离web容器可能需要部署两个应用。不同的应用程序可能依赖于同一个第三方类库的不同版本。因此,需要保证每个应用程序的类库是独立的。相互隔离Web容器有自己的依赖类库,不能与应用类库混淆。基于安全的考虑,容器类库应该和程序类库隔离,对公司的一些核心类库进行加密保护,可能会传输字节码加密,这样在加载类的时候必须对字节码进行解密。从其他来源加载的字节码放在数据库中,硬盘上的其他路径,甚至云端。类重载类对象在JVM中的唯一性:类加载器实例+全类名程序运行时,如果类内容发生变化,创建自定义加载器实例重新加载类,以达到最佳的热部署效果。在座的每个人都有一个概念,理解就够了。如果要深入探究,就需要涉及到源码分析。有兴趣的可以在评论区留言,阿星会单独补上源码分析~厉害的爸爸们,有的爸爸好可怕,为了帮后代处理好一切,直接破坏了亲子委派模式,深受孩子们的喜爱。Java应用程序中有许多服务提供者接口(ServiceProviderInterface,SPI)。这些接口允许第三方为其提供实现。比如常见的SPI有JDBC、JNDI等,这些SPI接口属于Java核心库。一般有rt.jar包由启动类加载器(Bootstrap)加载,而SPI的第三方实现代码作为Java应用程序依赖的jar包存放在classpath路径下。因为SPI接口中的代码需要加载第三方实现类并调用其相关函数,但是SPI的核心接口类是由启动类加载器(Bootstrap)加载的,Bootstrap加载器无法直接加载实现类的SPI。在这种情况下,我们需要一个专门的类加载器来加载第三方类库,这就是线程上下文类加载器,而线程上下文类加载器默认设置为系统类加载器(System)。接下来的计划就是跟各位读者汇报一下后续的安排,嗯……,如果不出意外的话,基本上每周都会更新,期间再转发一些优质的文章。大家看完记得连按三下啊,报告完毕!我是阿星,一个热爱技术的Java程序员,公众号「程序员阿星」会定期分享操作系统、计算机网络、Java、分布式、数据库等方面的优质原创文章,2021,一起成长BeBetter的路上有你!
