本文只涉及java 的classloader体系以及classloader对class的加载行为,不涉及一个class的加载过程和生命周期
ClassLoader 层级
jvm classloader 分为3层,顶层是拿C语言写的Bootstrap classloader,我们称之为JVM类加载器,主要加载的是classpath 下rt.jar,rt.jar 中主要是java的一些基础类,例如Integer, String 等
第二层是ext class loader 已经拿java语言去实现了,主要是加载JDK下ext包下的类,ext包下有类似DNS相关的类,zip解析相关的类,加密解密的类等其他一些java 扩展类,是现在Lanucher 的 ExtClassLoader
第三层是 系统类加载器,也可以称为应用类加载器,主要加载应用中的类,所有的自定义类都是继承自这个类,实现是在Launcher中的AppClassLoader
classLoader 双亲委托机制
首先来解释双亲委托机制,这个机制主要是定义了一个类在加载中所遵循的规则,例如,A.class 类的加载首先是由应用类加载器,但是类并不是由应用类加载器进行加载,而是会转到上一层的类加载器(ExtClassLoader),ExtClassLoader也不会直接加载,同样的他会交由Bootstrap类加载器进行加载,只有当这个加载器加载不了的时候,才会交由下层类加载器加载,最终A.class会交由应用本身的类加载器进行加载。这种机制的好处就在于,Java本身的类不会被别的加载器加载,只能由Bootstrap中加载,这样能保证被加载类的安全性,因为只有这样,加载出来的Class才不会被篡改,例如,如果Integer.class可以在应用类加载器中加载,那么应用类加载器可以在自己本身的加载路径中模拟一个全路径名一模一样的class,而这个class可以是一个会引起JVM OOM的类,那JVM的安全将不能被保证了,因为有了每一层加载器加载制定范围内限定权限下的class,不至于让开发者能人为破坏JVM
class在classloader中加载的顺序(ClassLoader中类加载源码解析)
现在我们来看一下源码中是怎么实现对class的加载,AppClassLoader和ExtClassLoader都是继承自URLClassLoader,所以我们直接看下里面的实现,主要的是三个方法,loadClass,defineClass,findClass
loadClass
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { //先查看当前class是否已经被加载过 Class c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { //如果没有被加载过,则交给父加载器进行加载 if (parent != null) { c = parent.loadClass(name, false); } else { // 如果没有附加载器,直接交给Bootstrap classLoader 加载 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // 此处类未加载到不进行excepiton处理,避免类加载中断 } if (c == null) { // 通过双亲委托,交由父加载器没有加载到对应的类时,// 当前类自己进行class load long t1 = System.nanoTime(); // 在指定的类路径下查找类 c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } // 类加载时可以指定知否需要初始化class,不进行初始化的话,在class被用到时再resolve if (resolve) { resolveClass(c); } return c; } }
findClass
protected Class<?> findClass(final String name) throws ClassNotFoundException { try { // 通过传入的path路径 (name即path类的全路径)加载类 return AccessController.doPrivileged( new PrivilegedExceptionAction<Class>() { public Class run() throws ClassNotFoundException { String path = name.replace('.', '/').concat(".class"); Resource res = ucp.getResource(path, false); if (res != null) { try { // 通过全路径名加载class,define方法将二进制流转成class return defineClass(name, res); } catch (IOException e) { throw new ClassNotFoundException(name, e); } } else { throw new ClassNotFoundException(name); } } }, acc); } catch (java.security.PrivilegedActionException pae) { throw (ClassNotFoundException) pae.getException(); } }
defindClass方法在这边就不介绍源码了,源码可读意义不大,主要的功能是将指定了资源路径名的class解析成为一个JVM 的class对象,用到了很多sun.misc包下的API
上下文类加载器
java 默认的类加载机制使用的是双亲委托的方式,但是有这么一种场景,Java一般定义了供第三方SPI去实现的统一接口,一般这些接口在rt.jar中,而第三方代码库的实现代码一般存在在自己集成的jar中,这个时候,如果依据我们之前认知的类加载方式--双亲委托机制,rt.jar中的接口类肯定会交由Boostrap进行加载,这个时候,在加载到具体实现的时候,默认是通过当前类加载器进行具体类的加载,Boostrap是找不到第三方类库的实现类的,这样类加载就失败了;所以在这种场景下,上下文类加载器应运而生,在加载第三方类库前,调用类先通过Thread的getContextClassLoader获取上下文加载器,一般默认的加载器是AppClassLoader,然后通过该加载器进行第三方类库代码的加载,应用类加载器本身就有加载应用classpath下面的依赖包,所以就会加载第三方类库的实现类,以JAXP的DocumentaryBuilderFactory为例
// 实际获取SPI实现类的方法 private static Class getProviderClass(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException { try { if (cl == null) { if (useBSClsLoader) { return Class.forName(className, true, FactoryFinder.class.getClassLoader()); } else { // 获取上下文类加载器 cl = ss.getContextClassLoader(); if (cl == null) { throw new ClassNotFoundException(); } else { // 实际loadClass return cl.loadClass(className); } } } else { return cl.loadClass(className); } } catch (ClassNotFoundException e1) { if (doFallback) { // Use current class loader - should always be bootstrap CL return Class.forName(className, true, FactoryFinder.class.getClassLoader()); } else { throw e1; } } }
相关推荐
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。理解ClassLoader的工作原理以及如何定制它,对于深入学习Java的运行机制和进行高级应用开发具有重要意义。本篇文章将...
Java ClassLoader是一个核心的Java运行时组件,负责加载类到Java虚拟机(JVM)中。它是Java平台的独特特性,因为它允许动态加载类,增强了软件的可扩展性和灵活性。这篇博文(虽然链接不可用)可能深入探讨了...
### Java ClassLoader与ClassPath详解 #### 一、概述 在Java编程中,类加载机制是十分关键的一个环节。类加载器(`ClassLoader`)负责将编译后的`.class`文件加载到Java虚拟机(JVM)中执行,而类路径(`ClassPath...
破解java加密的ClassLoader.java,在classloader植入破解代码
Java ClassLoader机制是Java虚拟机(JVM)中一个至关重要的组成部分,它的主要任务是将类的.class文件加载到JVM中,使得程序能够运行。ClassLoader不仅负责类的加载,还涉及类的验证、初始化等一系列过程。理解...
### Java ClassLoader原理详解 #### 摘要 本文探讨了Java虚拟机(JVM)中的一个重要特性:动态类加载(Dynamic Class Loading)。这一机制为Java平台提供了强大的能力,允许在运行时安装软件组件,例如从网络下载...
Java ClassLoader机制是Java运行时环境中的核心组件之一,它负责加载类到JVM(Java虚拟机)中,使得程序能够执行。理解ClassLoader的工作原理对于优化应用性能、处理类加载问题以及实现自定义加载器至关重要。 首先...
Java ClassLoader学习总结 Java 类加载机制是 Java 中一个非常重要的机制,它负责加载 Class 文件到 JVM,以供程序使用。ClassLoader 是 Java 中的一个抽象类,它的主要作用是加载 Class 文件到 JVM 中。...
Java 类加载器(ClassLoader)是Java虚拟机(JVM)的重要组成部分,它负责在运行时查找并加载类到JVM中。这个教程将深入探讨ClassLoader的工作原理、类型以及如何自定义类加载器。 一、Java ClassLoader 基础 1. 类...
### Java ClassLoader理解详解 #### 一、引言 在商业流行的编程语言中,Java以其独特的运行机制脱颖而出:它在Java虚拟机(JVM)上运行。这意味着编译后的程序采用一种特殊的、与平台无关的格式,而不是针对特定...
### Java ClassLoader详解:以淘宝网为例 #### 一、ClassLoader概述 在Java环境中,类加载器(ClassLoader)是负责加载Java类到JVM的重要组件。它不仅实现了类的加载机制,还支持了动态加载与卸载的功能。本文将...
Java 类加载器(ClassLoader)是Java虚拟机(JVM)中的一个重要组成部分,它负责加载类的字节码文件,使得程序能够运行。深入理解ClassLoader对于优化应用性能、处理类加载问题以及实现自定义加载策略至关重要。 一...
### Java ClassLoader (类加载器)详解 #### 一、教程提示 如果你正在查看这份文档,在线版中你可以点击下面的任何主题直接跳转到相应的部分。 1. **教程提示** 2. **介绍** 3. **类加载器结构** 4. **编译类加载...
Java ClassLoader是Java虚拟机(JVM)的重要组成部分,它负责加载类到JVM中运行。理解ClassLoader的工作原理对于深入学习Java以及进行JVM优化、插件开发等高级技术至关重要。下面将详细介绍Java ClassLoader的基本...
在深入探讨Java类加载器(ClassLoader)之前,我们首先需要了解它在Java运行时系统中的核心作用。类加载器是Java虚拟机(JVM)的一个关键组成部分,负责查找、加载和链接类文件到JVM中。它的存在使得Java应用程序...
Java中的类加载器(ClassLoader)是Java虚拟机(JVM)的一个重要组成部分,它负责将类的.class文件从文件系统或者网络中加载到内存中,并转换为对应的Class对象。类加载器的工作流程主要包括加载、验证、准备、解析...