目录
1 写在前面
为了更好的理解双亲委派机制,需要先了解类加载与类加载器相关知识。
2 什么是双亲委派机制
某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,子加载器才会尝试自己去加载。
总结就是
- 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行;
- 如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器;
- 如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式
3 类加载器介绍
-
Bootstrap 类加载器是用 C++ 实现的,是虚拟机自身的一部分,主要负责加载核心的类库。如果获取它的对象,将会返回 null;
-
扩展类加载器和应用类加载器是独立于虚拟机外部,为 Java 语言实现的,均继承自抽象类 java.lang.ClassLoader ,开发者可直接使用这两个类加载器。
-
Application 类加载器对象可以由
ClassLoader.getSystemClassLoader()
方法的返回,所以一般也称它为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。 -
用户自定义类加载器(Custom ClassLoader):可加载指定路径下的class文件。
4 双亲委派机制工作流程
-
当
Application ClassLoader
收到一个类加载请求时,他首先不会自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader
去完成。 -
当
Extension ClassLoader
收到一个类加载请求时,他首先也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader
去完成。 -
如果
Bootstrap ClassLoader
加载失败(在<JAVA_HOME>\lib中未找到所需类),就会让Extension ClassLoader
尝试加载。 -
如果
Extension ClassLoader
也加载失败,就会使用Application ClassLoader
加载。 -
如果
Application ClassLoader
也加载失败,就会使用自定义加载器去尝试加载。 -
如果均加载失败,就会抛出
ClassNotFoundException
异常。
例子:
当一个Hello.class这样的文件要被加载时。不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器的loadClass
方法。父类中同理会先检查自己是否已经加载过,如果没有再往上。注意这个过程,直到到达Bootstrap classLoader
之前,都是没有哪个加载器自己选择加载的。如果父加载器无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException
。
5 双亲委派机制作用
-
避免类的重复加载。当父类加载器加载了该类时,子类加载器就不会再加载一次。
-
防止java核心API被随意替换。
假设通过网络传递一个名为java.lang.Integer
的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer
,而直接返回已加载过的Integer.class
,这样便可以防止核心API库被随意篡改。可能你会想,如果我们在classpath路径下自定义一个名为java.lang.SingleInterge
类(该类是胡编的)呢?该类并不存在java.lan