双亲委派机制的定义
当某个类加载器需要加载class文件时,它会先把这个加载任务委派给他的父级类加载器,递归这个操作,如果上级的类加载器无法加载,自己才会去加载这个类,如下图:
双亲委派机制的实现
下面是java.lang.ClassLoader中loadClass方法的源码,具体实现对照代码解释。
当一个class文件需要被加载时(如果不考虑自定义类加载器),进入AppClassLoader中,首先检查是否加载过,如果有就无需加载了。如果没有,自己先不加载,去调用Extension ClassLoader的loadClass方法。Extension ClassLoader中同理会先检查自己是否已经加载过,如果没有,则去调用Bootstrap classLoader的loadClass方法,这里就没有父级了,Bootstrap classLoader就会看自己是否可以加载,如果可以就加载返回,如果无法加载,就会顺次下沉到子加载器Extension ClassLoader、AppClassLoader去加载,如果没有任何加载器能加载,就会抛出ClassNotFoundException。
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 {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
//如果未从非空的父加载器中找到类throw ClassNotFoundException
}
if (c == null) {
//如果仍然没有找到,那么调用自身的findClass来加载类.
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;
}
}
双亲委派机制的作用
1、保证核心class文件的安全性,如果有人篡改替换了系统级别的类,但是在这种机制下这些系统的类已经被Bootstrap ClassLoader加载过了,所以并不会再去加载,从一定程度上防止了危险代码的植入,从而保证底层class的执行安全。
2、防止重复加载同一class文件。通过委派机制向父级ClassLoader询问,如果加载过了,就不用再加载一遍,保证只会加载一份。
如何打破双亲委派机制
在继承自ClassLoader的自定义类加载器中重写loadClass方法