JVM类加载机制--从ClassLoader源码看双亲委托模型
在JVM的类加载机制中,为什么要使用双亲委派模型
类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)。从 Java 2(JDK 1.2)开始,类加载过程采取了父亲委托机制(PDM)。PDM 更好的保证了 Java 平台的安全性,在该机制中,JVM 自带的 Bootstrap 是根加载器,其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。JVM 不会向 Java 程序提供对 Bootstrap 的引用。这样可以有效避免类的重复加载和保护系统类不被篡改。
查看classloader源码:在rt.jar包的java.lang下的ClassLoader就是加载类(抽象类)
在调用的时候,首先都是先调用loadClass方法的,如图
该方法内部调用的是一个重载方法loadClass(name,false)方法:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name); //检查当前类是否加载
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
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();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
首先检查当前类是否已经加载了(在缓存中找),如果没有,返回null表示该类未加载,就会执行if (c == null)中的代码,如果parent不为null,就递归找父类加载器加载该类,如果parent为null,默认就使用根加载器加载,根类加载器会通过 findBootstrapClassOrNull 来加载 class,而findBootstrapClassOrNull 则会通过 JNI 方法”private native Class findBootstrapClass(String name)“来使
用 BootStrapClassLoader 来加载 class。然后如果 parent 未找到 class,则会调用 findClass 来加载 class,findClass 是一个 protected 的空方法,直接抛出一个ClassNotFoundException异常,所以当我们又没有自定义加载器的时候,系统就会抛出一个ClassNotFoundException异常了,我们可以自定义类加载器重写这个方法实现自定义类加载器加载该类的功能。