# Classloader Java ClassLoader是构成JRE(Java Runtime Environment)的一部分,ClassLoader负责动态的将java classes加载到JVM中。java classes并不是一次性全部加载到内存中的,而是在应用需要时动态加载到内存中。 > JRE调用classloader,然后classloader负责将classes动态加载到内存中。 在java`按需将需要的类动态加载到内存中`的特性中,classloader扮演了重要的作用,令Java应用更加的弹性和高效。 ## Types of ClassLoaders in Java java ClassLoaders可以被归类为不同的类型,每种类型负责从指定的路径加载classes: ### Bootstrap ClassLoader(原始类加载器) - Bootstrap Classloader是机器码,负责初始化JVM的操作 - 直到java 8中,其从`rt.jar`中加载核心java文件;但是从java 9开始,其负责从java runtime image中加载核心java文件 - Bootstrap ClassLoader独立的操作,其并没有parent ClassLoader ### Platform ClassLoader(Extension ClassLoader) - 在java 9之前,存在Extension ClassLoader,但是在java 9及之后,其被称作Platform ClassLoader - 该classloader会从JDK module系统中加载平台特定的拓展 - platform class loader会从java runtime image中加载文件,同时也会从`java.platform`属性所指定的module或`--module-path`所指定的module处加载文件 ### System ClassLoader(Application ClassLoader) - System ClassLoader也被称为`Application ClassLoader`,其从应用的classpath加载classes - 其是Platform ClassLoader的一个child - 将会从`CLASSPATH`环境变量、`-classpath`或`-cp`选项所指定的目录处加载 ## Principles of Functionality of a Java ClassLoader java ClasLoader基于如下准则进行操作: ### Delegation Model - ClassLoaders遵循委托继承算法 - 当JVM遇到一个class时,其会检查其是否已经被加载,如果该class还未被加载,那么JVM会将class的加载委托给`a chain of ClassLoaders` - 该委托架构从Application ClassLoader开始,向上移动到Platform ClassLoader,最终移动到Bootstrap ClassLoader - 在层次结构中的每一个ClassLoader,都会在其负责的locations处查找class,并且在必要时将class的加载过程委托给父级 ### Visibility Principle - 由Parent ClassLoaders负责加载的classes对于child classloader来说也是可见的;反之,由child classloader负责加载的classes对于parent classloader来说则不可见 - 上述的可见性定义确保了封装性,防止由不同的classloaders负责加载的classes出现冲突 ### Uniqueness Property - ClassLoader会确保class只会被加载一次,从而保证class在JVM中的唯一性 - 只有当parent ClassLoader无法查询到某个类时,当前classloader才会尝试去加载该类 ## Methods of java.lang.ClassLoader 为了加载类,ClassLoader中提供了如下方法: - `loadClass(String name, boolean resolve)`: 其会加载JVM所引用的类,并在必要时进行解析 - `defineClass()`: 该方法会将一个字节数组转化为Class实例对象。如果字节数组中的内容不是有效的class,那么将会抛出ClassFormatError异常 - `findClass(String name)`:该方法会对class进行查找,但是并不会对其进行加载 - `findLoadedClass(String name)`:该方法用于验证是否该类已经被加载 - `Class.forName(String name, boolean initialize, ClassLoader loader)`: 该方法会加载并初始化class,允许指定ClassLoader,如果该classLoader没有指定,则默认会使用Bootstrap ClassLoader 上述方法的使用示例如下: ```java // Code executed before class loading Class clazz = ClassLoader.getSystemClassLoader().loadClass("com.example.MyClass"); ``` ClassLoader in Java ### Delegation Model JVM和ClassLoader使用了委托层次结构算法来加载class,classLoader运行原则如下: - classLoader永远会遵循委托层次结构原则 - 当jvm遇到class时,其首先会检查该class是否已经被加载 - 如果该类未被加载,那么jvm将会请求classloader sub-system去加载该类,而classloader sub-system则会将该加载工作委托给Application ClassLoader - Application Classloader会将该类的加载任务委托给Extension ClassLoader,而Extension ClassLoader则是会再次将该加载任务委托给Bootstrap Classloader - Bootstrap Classloader会在bootstrap classpath(JDK/JRE/LIB/EXT)路径下查找该类,如果该class存在,那么其将会被加载,否则加载请求将会回到Extension Classloader - Extension Classloader也会从Extension classpath下查找该类,如果查找到该类,则加载该类,否则请求将会被委托给Application ClassLoader - Application ClassLoader将会在Application classpath路径下查找该类,如果类存在会加载该类,否则其会抛出ClassNotFoundException ### Visibility Principle 可见性原则保证了`由parent classloader加载的类对于child classloader来说是可见的,而child classloader加载的类对parent classloader来说是不可见的`。 假设类`GEEK.class`被Extension ClassLoader加载,那么该类仅被Extension ClassLoader和Application Classloader可见,对于Bootstrap ClassLoader来说`GEEK.class`是不可见的。如果该类尝试通过Bootstrap ClassLoader再次加载,其会报`ClassNotFoundException` ### Uniqueness Property 唯一性保证了class是唯一的,其保证了由parent classloader加载的类不会再被child classloader加载。只有当parent classloader无法查找到该类时,当前classloader才会尝试对其进行加载