什么是双亲委派机制?
# 什么是双亲委派机制?
双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。
加载器 | 加载哪些类 |
---|---|
bootstrap classloader | 加载jre/lib/rt.jar |
extension classloader | jre/lib/ext/*.jar |
application classloader | 加载应用程序目录 |
自定义ClassLoader | 定制化加载 |
再来读一下java.lang.ClassLoader这段代码 是不是通透了许多?
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
// -----??-----
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 首先,检查是否已经被类加载器加载过
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
// 存在父加载器,递归的交由父加载器
if (parent != null) {
c = parent.loadClass(name, false);
} else {
// 直到最上面的Bootstrap类加载器
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.
c = findClass(name);
}
}
return c;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Q1:使用双亲委派有什么好处?
A:双亲委派机制能保证多加载器加载某个类时,最终都是由一个加载器加载,确保最终加载结果相同。
考虑到安全因素。
假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。
Q2:什么场景需要破坏双亲委派?
双亲委派模型很好的解决了各个类加载器的基础类的统一问题(越基础的类由越上层的加载器进行加载)
基础类之所以称为“基础”,是因为它们总是作为被用户代码调用的API 但没有绝对,如果基础类调用会用户的代码怎么办呢? 比如JDBC驱动加载。 这种场景就需要用到SPI机制,是不符合双亲委派的。
Q3:JDBC、Tomcat中为什么要破坏双亲委派模型
A:JDBC
先来回顾一下JDBC的用法
String url = "jdbc:mysql:///consult?serverTimezone=UTC";
String user = "root";
String password = "root";
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection(url, user, password);
2
3
4
5
6
DriverManager 类中要加载各个实现了Driver接口的类,然后进行管理,DriverManager位于 JAVA_HOME中jre/lib/rt.jar 包,由BootStrap类加载器加载.
JDBC的Driver接口定义在JDK中,其实现由各个数据库的服务商来提供,比如MySQL驱动包位于服务商MySQL提供的 Jar 中包含Driver的实现,按照双亲委派模型应该由application classloader加载
实际上却是由BootStrap类加载器加载。
这是因为:根据类加载机制,当被装载的类引用了另外一个类的时候,虚拟机就会使用装载第一个类的类装载器装载被引用的类。
这就破坏了双亲委派模型。
Tomcat
每个webappClassLoader加载自己目录下的class文件
Tomcat支持部署多个Web应用,多个Web应用可能使用不同版本的JDK、也可能在应用内部定义全限定名一样的类,所以要做到应用隔离。