原文出处:http://blog.chenlb.com/2009/06/java-classloader-architecture.html
jvm classLoader architecture:
- Bootstrap ClassLoader/启动类加载器
主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作。 - Extension ClassLoader/扩展类加载器
主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作。 - System ClassLoader/系统类加载器
主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作。 - User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)
在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性。
类加载器的特性:
- 每个ClassLoader都维护了一份自己的名称空间, 同一个名称空间里不能出现两个同名的类。
- 为了实现java安全沙箱模型顶层的类加载器安全机制, java默认采用了 " 双亲委派的加载链 " 结构。
类图中, BootstrapClassLoader是一个单独的java类, 其实在这里, 不应该叫他是一个java类。因为,它已经完全不用java实现了。它是在jvm启动时, 就被构造起来的, 负责java平台核心库。
自定义类加载器加载一个类的步骤
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);
- }
- }
线程上下文类加载器
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" );
- }
- // Also set the context class loader for the primordial thread.
- Thread.currentThread().setContextClassLoader(loader);
以上代码摘自sun.misc.Launch的无参构造函数Launch()。
使用线程上下文类加载器, 可以在执行线程中, 抛弃双亲委派加载链模式, 使用线程上下文里的类加载器加载类.
典型的例子有, 通过线程上下文来加载第三方库jndi实现, 而不依赖于双亲委派.
大部分java app服务器(jboss, tomcat..)也是采用contextClassLoader来处理web服务。
还有一些采用 hotswap 特性的框架, 也使用了线程上下文类加载器, 比如 seasar (full stack framework in japenese).
线程上下文从根本解决了一般应用不能违背双亲委派模式的问题.
使java类加载体系显得更灵活.
随着多核时代的来临, 相信多线程开发将会越来越多地进入程序员的实际编码过程中. 因此,
在编写基础设施时, 通过使用线程上下文来加载类, 应该是一个很好的选择。
当然, 好东西都有利弊. 使用线程上下文加载类, 也要注意, 保证多根需要通信的线程间的类加载器应该是同一个,
防止因为不同的类加载器, 导致类型转换异常(ClassCastException)。
为什么要使用这种双亲委托模式呢?
- 因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
- 考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的ClassLoader。
java动态载入class的两种方式:
- implicit隐式,即利用实例化才载入的特性来动态载入class
- explicit显式方式,又分两种方式:
- java.lang.Class的forName()方法
- java.lang.ClassLoader的loadClass()方法
用Class.forName加载类
Class.forName使用的是被调用者的类加载器来加载类的。
这种特性, 证明了java类加载器中的名称空间是唯一的, 不会相互干扰。
即在一般情况下, 保证同一个类中所关联的其他类都是由当前类的类加载器所加载的。
- public static Class forName(String className)
- throws ClassNotFoundException {
- return forName0(className, true , ClassLoader.getCallerClassLoader());
- }
- /** Called after security checks have been made. */
- private static native Class forName0(String name, boolean initialize,
- ClassLoader loader)
- throws ClassNotFoundException;
上面中 ClassLoader.getCallerClassLoader 就是得到调用当前forName方法的类的类加载器
static块在什么时候执行?
- 当调用forName(String)载入class时执行,如果调用ClassLoader.loadClass并不会执行.forName(String,false,ClassLoader)时也不会执行.
- 如果载入Class时没有执行static块则在第一次实例化时执行.比如new ,Class.newInstance()操作
- static块仅执行一次
各个java类由哪些classLoader加载?
- java类可以通过实例.getClass.getClassLoader()得知
- 接口由AppClassLoader(System ClassLoader,可以由ClassLoader.getSystemClassLoader()获得实例)载入
- ClassLoader类由bootstrap loader载入
NoClassDefFoundError和ClassNotFoundException
- NoClassDefFoundError:当java源文件已编译成.class文件,但是ClassLoader在运行期间在其搜寻路径load某个类时,没有找到.class文件则报这个错
- ClassNotFoundException:试图通过一个String变量来创建一个Class类时不成功则抛出这个异常
相关推荐
Java的类加载器(ClassLoader)体系结构是JVM(Java虚拟机)中至关重要的一部分,它负责将类的字节码转换为运行时的类实例。本文将深入探讨启动类加载器、扩展类加载器、系统类加载器以及用户自定义类加载器,同时还...
二、ClassLoader的体系结构 ClassLoader形成一个树状结构,BootstrapClassLoader是根节点,ExtensionClassLoader是其子节点,SystemClassLoader是ExtensionClassLoader的子节点。用户还可以自定义ClassLoader,插入...
Java 体系结构图是理解Java编程语言及其生态系统的关键工具,尤其对于初学者而言,它能够清晰地展现Java的各个组成部分以及它们之间的关系。这个压缩包包含的“体系结构图”很可能是以图形形式展示了Java的核心概念...
Java的类加载器体系结构由三个主要类型的类加载器组成: 1. **引导类加载器(Bootstrap ClassLoader)**:这是最基础的类加载器,负责加载Java的核心库类,如`java.lang`包下的类。 2. **扩展类加载器(Extension ...
### 基于沙箱的Java安全体系结构 #### 概述 Java作为一种跨平台的编程语言,其安全模型的设计尤为关键。Java的安全沙箱机制是确保Java应用程序能够在不损害系统安全的前提下运行的重要保障。本文将详细介绍Java...
双亲委托机制是`ClassLoader`体系中的一个重要特性,它确保了核心库的加载只由顶层的启动类加载器进行。这一机制的工作流程如下: 1. **当一个类加载器收到类加载请求时**,它首先不会尝试自己去加载这个类,而是将...
【深入理解Java虚拟机体系结构】 Java虚拟机(Java Virtual Machine,简称JVM)是Java平台的核心组成部分,它使得Java程序具有平台无关性,保证了“一次编译,到处运行”的特性。Java虚拟机主要负责加载类文件并...
#### 二、Tomcat的ClassLoader体系结构 Tomcat采用了独特的类加载机制来处理不同的类库加载需求。其ClassLoader体系结构可以分为以下几个层次: 1. **Bootstrap ClassLoader**:这是JVM自带的类加载器,负责加载...
本笔记将深入探讨Java的各个核心概念和组成部分,构建一个全面的Java知识体系。 一、Java基础 1. Java语法:Java语法基于C++,但更加简化和安全。包括变量声明、数据类型(如基本类型、引用类型)、运算符、流程...
- **启动类加载器(Bootstrap ClassLoader)**:它是所有类加载器的父类,用于加载Java的核心库(如java.lang.*包下的类),这些类通常位于`JAVA_HOME/jre/lib/rt.jar`中。 - **扩展类加载器(Extension ...
#### 二、ClassLoader体系结构 类装载器在JVM中并不唯一,JVM自带了三个主要的装载器,并且支持用户自定义新的装载器。这些装载器的组织结构通常呈树状,其中三个内置装载器分别为: 1. **Bootstrap ClassLoader...
Java虚拟机(JVM)是Java程序运行的核心,它的体系结构和内存模型是理解Java性能优化和内存管理的关键。在《深入Java虚拟机 (第二版)》这本书中,作者详细探讨了JVM的各个方面,帮助开发者提升代码效率和稳定性。 ...
了解JVM的体系结构和垃圾收集(Garbage Collection, GC)机制对于优化Java应用性能至关重要。 **1. JVM体系结构** JVM主要由以下几个组件构成: - **类装载器(Class Loader)**:负责加载.class文件到JVM内存中...
* 体系结构中立性:Java 程序在 Java 平台上被编译为体系结构中立的字节码格式,然后可以在实现这个 Java 平台的任何系统中运行。 * 可移植性:Java 语言的可移植性来源于体系结构中立性,另外,Java 还严格规定了...
Java类加载器的层次结构包含三层:Bootstrap ClassLoader、Extension ClassLoader和Application ClassLoader。 JVM架构则是Java虚拟机的内部结构,它负责执行Java程序,是实现跨平台的关键。JVM的主要组件包括类...
通常用于实现层次化 `ClassLoader` 体系中的上下文传递。 - **`getParent`**:这个方法用于获取当前 `ClassLoader` 的父 `ClassLoader` 实例。在实现委托机制时非常重要。 - **`resolveClass`**:这个方法用于解决类...
这种可移植性来源于体系结构中立性,另外,Java 还严格规定了各个基本数据类型的长度。Java 系统本身也具有很强的可移植性,Java 编译器是用 Java 实现的,Java 的运行环境是用 ANSI C 实现的。 Java是全能的!!!...
3. **Java虚拟机的体系结构**: - **类加载器子系统**:负责加载类和接口,赋予唯一的名字。分为Bootstrap ClassLoader、Extension ClassLoader和App ClassLoader等。 - **执行引擎**:执行加载类中的字节码指令。...