我是
方圆
,愿你我皆能理解双亲委派机制
1. 在之前,不得不先理解类加载器
我们先来看一段简单的代码
public class Car {
public static void main(String[] args) {
//实例化
Car car = new Car();
//获取Car Class模板
System.out.println(car.getClass());
//应用程序类加载器,AppClassLoader
System.out.println(car.getClass().getClassLoader());
//扩展类加载器,ExtClassLoader
System.out.println(car.getClass().getClassLoader().getParent());
//虽然为null,是java调用不到,实际上它是启动类加载器,BootstrapClassLoader
//主要负责加载核心类库
System.out.println(car.getClass().getClassLoader().getParent().getParent());
}
}
从上方代码中,我们可以看到,从实体类一直获取到启动类加载器,从下图中理解更直观。
我们可以发现有三种类加载器
- 最底层的,
Application ClassLoader
:加载classpath上指定的类库 - 其次,
Extension ClassLoader
:加载jre/lib/ext/*.jar - 最后是,
Bootstrap ClassLoader
:加载jre/lib/rt.jar
我们不妨画一幅图,理解一下
大家可以看见,我画了双向的箭头
,下面就要聊聊双亲委派机制,理解了之后自然就明白了
2. 双亲委派机制
2.1 什么是双亲委派机制?
双亲委派机制是指当一个类加载收到一个类加载的请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有在父类加载器范围内找不到指定类时,子类加载器才会自己尝试加载。
读完这段概念,是不是还有点儿懵,下面我们来详细解析一下这个过程
2.2 双亲委派机制的工作过程
- 当Application ClassLoader 收到一个类加载请求时,他首先
不会
自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader去完成。 - 当Extension ClassLoader收到一个类加载请求时,他首先也
不会
自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成。 - 如果Bootstrap ClassLoader加载失败
(在<JAVA_HOME>\lib中未找到所需类)
,就会让Extension ClassLoader尝试加载。 - 如果Extension ClassLoader
也
加载失败,就会使用Application ClassLoader加载。 - 如果Application ClassLoader
也
加载失败,就会使用自定义加载器去尝试加载。 - 如果均加载失败,就会抛出
ClassNotFoundException
异常。(这也是我们常见的一个异常)
2.3 我们拿代码来举一个例子
目录结构如下
package java.lang;
public class String {
@Override
public String toString() {
return "简单测试,双亲委派机制";
}
public static void main(String[] args) {
String s = new String();
//在双亲委派机制的作用下,会发生异常
s.toString();
}
}
异常如下
我们也能从中理解到双亲委派机制的作用:
保证安全,防止重复加载同一个.class,保证核心.class不能被篡改
2.4 看一下源码加深理解
下面是ClassLoader中,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 {
// c==null表示没有加载,如果有父类的加载器则让父类加载器加载
if (parent != null) {
c = parent.loadClass(name, false);
} else {
//如果父类的加载器为空 则说明递归到bootStrapClassloader了
//bootStrapClassloader比较特殊无法通过get获取
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {}
if (c == null) {
//如果bootstrapClassLoader 仍然没有加载过,则递归回来,尝试自己去加载class
long t1 = System.nanoTime();
c = findClass(name);
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}