ClassLoader体系结构

本文详细介绍了Java中的四种类加载器:启动类加载器、扩展类加载器、系统类加载器及用户自定义类加载器的功能与职责。此外,还探讨了类加载器的双亲委派模型以及如何通过自定义类加载器实现类的动态加载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、4类ClassLoader
(1) Bootstrap ClassLoader/启动类加载器
     主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作.
(2) Extension ClassLoader/扩展类加载器
     主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作
(3) System ClassLoader/系统类加载器
     主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作.
(4) User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)
     在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性.

 

二、类加载器的特性:
1. 每个ClassLoader都维护了一份自己的名称空间, 同一个名称空间里不能出现两个同名的类。
2. 为了实现java安全沙箱模型顶层的类加载器安全机制, java默认采用了 ” 双亲委派的加载链 ” 结构.

    如下图:

 

    类图如下:

    类图中, BootstrapClassLoader是一个单独的java类,其实在这里,不应该叫他是一个java类。因为它已经完全不用java实现了(c++实现)。它是在jvm启动时,就被构造起来的,负责java平台核心库。启动类加载实现bootstrap classLoader类加载原理探索。
    自定义类加载器加载一个类的步骤:

    ClassLoader 类加载逻辑分析,以下逻辑是除 BootstrapClassLoader 外的类加载器加载流程:

// 检查类是否已被装载过
Class c = findLoadedClass(name);
if (c == null ) {
     // 指定类未被装载过
     try {
         if (parent != null ) {
             // 如果父类加载器不为空, 则委派给父类加载
             c = parent.loadClass(name, false );
         } else {
             // 如果父类加载器为空, 则委派给启动类加载加载
             c = findBootstrapClass0(name);
         }
     } catch (ClassNotFoundException e) {
         // 启动类加载器或父类加载器抛出异常后, 当前类加载器将其
         // 捕获, 并通过findClass方法, 由自身加载
         c = findClass(name);
     }
}

 

    用Class.forName加载类,Class.forName使用的是被调用者的类加载器来加载类的.这种特性, 证明了java类加载器中的名称空间是唯一的, 不会相互干扰.即在一般情况下, 保证同一个类中所关联的其他类都是由当前类的类加载器所加载的.

public static Class forName(String className)
     throws ClassNotFoundException {
     return forName0(className, true , ClassLoader.getCallerClassLoader());
}
 
private static native Class forName0(String name, boolean initialize,
ClassLoader loader)
     throws ClassNotFoundException;

 

上图中 ClassLoader.getCallerClassLoader 就是得到调用当前forName方法的类的类加载器
 
线程上下文类加载器
    java默认的线程上下文类加载器是 系统类加载器(AppClassLoader).

// Now create the class loader to use to launch the application
try {
    loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
    throw new InternalError(
"Could not create application class loader" );
}

 

    以上代码摘自sun.misc.Launch的无参构造函数Launch()。使用线程上下文类加载器, 可以在执行线程中, 抛弃双亲委派加载链模式, 使用线程上下文里的类加载器加载类.典型的例子有, 通过线程上下文来加载第三方库jndi实现, 而不依赖于双亲委派.
    大部分java app服务器(jboss, tomcat..)也是采用contextClassLoader来处理web服务。还有一些采用 hotswap 特性的框架, 也使用了线程上下文类加载器, 比如 seasar (full stack framework in japenese).
线程上下文从根本解决了一般应用不能违背双亲委派模式的问题.

 

使java类加载体系显得更灵活.
    随着多核时代的来临, 相信多线程开发将会越来越多地进入程序员的实际编码过程中. 因此,在编写基础设施时, 通过使用线程上下文来加载类, 应该是一个很好的选择.

    当然, 好东西都有利弊. 使用线程上下文加载类, 也要注意, 保证多根需要通信的线程间的类加载器应该是同一个,防止因为不同的类加载器, 导致类型转换异常(ClassCastException).

 

### JVM体系结构详解 JVM(Java Virtual Machine)是Java程序运行的基础,它是介于Java程序和操作系统之间的中间层。JVM的主要功能是将字节码解释为机器可读的指令,并提供必要的运行时支持。 #### 1. JVM的整体架构 JVM由以下几个核心组件构成[^1]: - **类加载器(Class Loader)** - **运行时数据区(Runtime Data Area)** - **执行引擎(Execution Engine)** 这些组成部分共同协作,使得Java程序能够在不同的平台上无缝运行。 --- #### 2. 类加载器(Class Loader) 类加载器负责动态加载`.class`文件到JVM中。它的主要职责是从磁盘或其他资源中获取字节码,并将其转换为可在JVM中使用的类对象。类加载器分为以下几种类型[^3]: - **启动类加载器(Bootstrap ClassLoader)**: 加载Java的核心库(如`rt.jar`),通常由本地代码实现。 - **扩展类加载器(Extension ClassLoader)**: 负责加载标准扩展库。 - **应用程序类加载器(Application ClassLoader)**: 用户自定义的应用程序类路径下的类都由该加载器加载。 --- #### 3. 运行时数据区(Runtime Data Area) 这是JVM在运行期间用来管理内存的空间,按照用途划分为几个区域: ##### (1)方法区(Method Area) 方法区用于存储已被虚拟机加载的类信息、常量池、静态变量以及即时编译后的代码等。尽管有时被称为“永久代”,但它并不是不可变的——其中的内容也可以被垃圾回收器清理掉,例如无用的类或常量[^4]。 ##### (2)堆(Heap) 堆是最重要的一部分内存分配区域,所有的对象实例都在这里创建。由于堆是所有线程共享的,因此它是垃圾收集的重点关注对象之一。 ##### (3)栈(Stack) 每个线程都有自己的私有栈,保存局部变量表、操作数栈、返回地址以及其他帧数据。每当调用一个新方法时,都会为其创建一个新的栈帧;当方法结束时,对应的栈帧就会被销毁。 ##### (4)PC寄存器(Program Counter Register) 记录当前线程所执行的字节码指令的位置。如果正在执行的是本地方法,则此寄存器为空。 ##### (5)本地方法栈(Native Method Stack) 类似于普通的Java栈,只不过它服务于原生函数调用而非纯Java逻辑处理。 --- #### 4. 执行引擎(Execution Engine) 执行引擎的作用是对字节码进行解析并最终转化为底层硬件能够理解的操作命令。以下是其工作流程的关键环节[^1]: - **解释器(Interpreter):** 将字节码逐条翻译成特定平台上的机器语言立即执行。 - **即时编译器(Just-In-Time Compiler, JIT):** 对频繁被执行的部分热点代码提前完成优化后再交付给CPU运行,从而提升整体性能表现。 两者可以协同合作,在不同场景下发挥各自优势。 --- ### 总结 综上所述,JVM通过精心设计的内部机制实现了跨平台特性的同时还兼顾了高效性和灵活性。无论是从理论层面还是实际应用角度来看,深入掌握JVM原理都是非常有价值的技能点。 ```python # 示例:简单的Java字节码演示如何映射至JVM模型 public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } } ``` 上述代码展示了最基础的Java程序及其背后涉及到了哪些JVM部件参与运作过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值