JVM启动过程
JVM启动流程1虚拟机申请完内存,就创建引导类加载器,引导类加载器是c++语言实现的,java无法获取,负责加载运行时的核心类。加载目录可以通过参数 -Xbootclasspath 或 系统变量sun.boot.class.path来指定。可以通过打印系统变量查看,引导类加载器在java中无法访问,所以获取其加载的类的类加载器时,会得到null。
String property = System.getProperty("sun.boot.class.path");
System.out.println(property.replace(";",";\n"));
//jdk1.8.0_91\jre\lib\resources.jar;
//jdk1.8.0_91\jre\lib\rt.jar;
//jdk1.8.0_91\jre\lib\sunrsasign.jar;
//jdk1.8.0_91\jre\lib\jsse.jar;
//jdk1.8.0_91\jre\lib\jce.jar;
//jdk1.8.0_91\jre\lib\charsets.jar;
//jdk1.8.0_91\jre\lib\jfr.jar;
//jdk1.8.0_91\jre\classes
System.out.println(String.class.getClassLoader());//null
接下来,JVM虚拟机调用已经加载在方法区的类sun.misc.Launcher 的静态方法getLauncher(), 获取sun.misc.Launcher 实例。sun.misc.Launcher 使用了单例模式设计,保证一个JVM虚拟机内只有一个sun.misc.Launcher实例。
package sun.misc;
public class Launcher {
private static Launcher launcher = new Launcher();//类加载时,初始化实例
private ClassLoader loader;
public static Launcher getLauncher() {
return launcher;
}
public Launcher() {
Launcher.ExtClassLoader var1;
try {
var1 = Launcher.ExtClassLoader.getExtClassLoader();//扩展类加载器,父类为null即引导类加载器
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);//系统类加载器,父类为扩展类加载器
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
}
Thread.currentThread().setContextClassLoader(this.loader);//主线程上下文加载器为系统类加载器
//...省略...
}
public ClassLoader getClassLoader() {
return this.loader;
}
}
launcher.getClassLoader() 方法将会返回 AppClassLoader 实例,AppClassLoader将ExtClassLoader作为自己的父加载器。
双亲委派机制
双亲委派除了引导类加载器(Bootstrap Class Loader )的所有类加载器,都有一个能力,就是判断某一个类是否被引导类加载器加载过,如果加载过,可以直接返回对应的Class<T> instance,如果没有,则返回null. 图上的指向引导类加载器的虚线表示类加载器的这个有限的访问 引导类加载器的功能。
双亲委派机制,加载类的逻辑如下,好处是避免重复加载类,避免核心类被篡改。
ClassLoad.loadClass
网友评论