编译器编译.java
产生.class
类加载器加载.class
到JVM
ClassLoder在加载.class
过程中会使用双亲委派机制加载
- BootStrapClassLoader 启动类加载器 在jvm启动时创建 加载
$JAVA_HOME/jre/lib
中类库 或通过参数-Xbootclasspath
指定库 由于引导类加载器涉及到虚拟机本地实现细节 无法直接获取到启动类加载器引用 不能直接操作 - ExtClassLoader 扩展类加载器 为sun.misc.Launcher中的内部类 加载
$JAVA_HOME/jre/lib/ext
中类库 或者通过参数-Djava.ext.dirs
指定库 - AppClassLoader 应用程序类加载器 为sun.misc.Launcher中的内部类 加载java环境变量CLASSPATH指定路径中类库 而CLASSPATH所指定路径可通过System.getProperty(“java.class.path”)获取 该变量也可通过参数
-cp
覆盖 - CustomClassLoader 自定义类加载器 如tomcat的StandardClassLoader 大部分情况使用AppClassLoader可满足需求
类实例化时执行过程如下
- 通过ExtClassLoader.getExtClassLoader()创建了ExtClassLoader
- 通过AppClassLoader.getAppClassLoader(ExtClassLoader)创建AppClassLoader 并将ExtClassLoader设为AppClassLoader的父ClassLoader
- 通过Thread.currentThread().setContextClassLoader(loader)把AppClassLoader设为线程的上下文ClassLoader
- 根据jvm参数
-Djava.security.manager
创建安全管理器 设置系统属性java.security.manager
为空字符串
ClassLoader双亲委派机制
- 当AppClassLoader加载class时 不会自己去尝试加载这个类 而把类委派给父类加载器ExtClassLoader加载
- 当ExtClassLoader加载class时 不会自己去尝试加载这个类 而把类委派给父类加载器BootStrapClassLoader加载
- 如BootStrapClassLoader加载失败(如在
$JAVA_HOME/jre/lib
中未找到该class) 会使用ExtClassLoader加载 - 若ExtClassLoader加载失败 会使用AppClassLoader加载 如AppClassLoader加载失败 则抛出异常ClassNotFoundException
双亲委派机制特点
安全 如 ClassLoader加载的class文件来源很多 编译器编译生成 或网络下载 自定义java.lang.Integer类覆盖jdk中默认Integer类
初始化自定义integer类时总会退出jvm 破坏程序运行 如使用双亲委派机制该Integer类永远不会被调用 只会加载源码中的类
package java.lang;public class Integer {public Integer(int value) {System.exit(0);}public static void main(String... args) {Integer i = new Integer(1);System.err.println(i);}
}
快速 Bootstrap已经加载过某类 其它类加载器再加载此类时会委托Bootstrap加载 Bootstrap直接返回内存中的实例 而不需重新加载 因此内存中只有一份类字节码对象