类加载机制概念
Java虚拟机把描述类的class文件加载到内存,对其进行校验、转换解析、初始化等操作,最终得到可以被虚拟机直接使用的java类型,这就是虚拟机的加载机制。

主要有五个步骤:
-
加载
将class文件读入到内存中,并将其放在运行时数据区的方法区内,然后在堆中创建一个java.lang.Class对象,用来封装在方法区的数据结构。
在这个阶段,主要完成如下三件事:- 通过一个类的全限定名获取此类的二进制字节流(Class文件)。而获取的方式可以通过jar、war、zip、网络等方式
- 将字节流静态存储结构转换为方法区(永久代、元空间)的内部数据结构
- 在内存中生成一个代表这个类的Class对象,作为方法区这个类的各种数据访问入口。其中Class对象没有规定是在堆内存中,它比较特殊,存在方法区中
-
验证:验证加载后的类格式、语义、字节码、符号引用(判断符号是否存在)
-
准备(分配内存空间):为类的静态变量在方法去分配内存并赋默认值(0或null)。其中静态常量在这个阶段就赋程序设定的值,比如static final int = 666;
-
解析:将类的二进制数据中的符号引用转为直接引用
-
类的初始化:把类加载到系统中,这个阶段才是真正执行java代码。主要工作是为静态变量赋程序设定的初值
双亲委派

关于双亲委派介绍网上资料很多,包括自定义类加载器、线程上下文类加载器等,这里就不做详细赘述了
线程上下文类加载器(双亲委派破坏者)
java中存在很多服务的提供者接口(Service Provider Interface,SPI),这些接口允许第三方为他们提供实现,然后进行载入。常见的SPI有JDBC、JNDI等,接口属于java的核心库,一般存储与rt.jar中,有Bootstrap加载器加载。

为什么需要线程上下文类加载器?
如果按照双亲委派的原则,我们该如何去加载到我们所实现的SPI呢,这就涉及到了线程上下文加载器(jdk 1.2开始引入),它是通过破坏双亲委派然后使Bootstrap加载器来反向委托线程上下文类加载器进行加载SPI实现类。
如何使用
初始化线程的上下文类加载器是系统类加载器(AppClassLoader),我们可以通过java.lang.Thread类中的getContextClassLoader()和setContextClassLoader(ClassLoader cl)方法进行获取或设置
源码解析
使用jdbc.jar为例来说明上下文类加载器是如何发现并加载实现类的
找到rt.jar中的java.sql.DriverManager类
public class DriverManager {
...
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
/**
* 加载并初始化driver
*/
private static void loadInitialDrivers() {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
pub

本文介绍了Java虚拟机的类加载机制,包括加载、验证、准备、解析和初始化五个步骤。此外,还探讨了双亲委派模型及线程上下文类加载器的作用,以及Tomcat中的类加载器结构。
最低0.47元/天 解锁文章
881

被折叠的 条评论
为什么被折叠?



