双亲委派机制原理
package basic;
import java.util.HashMap;
public class ClassLoaderDemo {
public static void main(String[] args) {
// C:\Program Files\Java\jdk1.8.0_191\jre\lib\rt.jar
HashMap<String, String> map = new HashMap<>();
Demo1 demo1 = new Demo1();
System.out.println(map.getClass().getClassLoader());
System.out.println(demo1.getClass().getClassLoader());
}
}
运行结果:
null // 启动类加载器由C++实现,Java无法打印出其引用。
sun.misc.Launcher$AppClassLoader@2a139a55
1. check ClassLoaderDemo 是否有父类加载器,存在,是扩展类加载器。
2. 不直接加载扩展类加载器,check扩展类加载器是否有父类,存在,是根类加载器。
3. check根类加载器是否有父类,没有。
3.1 根类加载器去加载ClassLoaderDemo (%JAVA_HOME%Jjre\lib)
3.2 找不到,告诉子类加载器扩展类加载器。
4. 扩展类加载器去%JAVA_HOME%\lib\ext寻找,找不到,告诉子类加载器“AppClassLoader”
5. AppClassLoader找到了,将ClassLoaderDemo 加载到内存中,生成class对象。
双亲委派机制优点
- 安全机制
比如自己写的String.class类不会被加载,这样可以防止核心库被随意篡改。
package basic;
public class String {
static {
System.out.println("my string started...");
}
public static void main(String[] args) {
String string = new String();
System.out.println(string);
}
}
运行结果:
错误: 找不到或无法加载主类 basic.String
String向上委托至启动类加载器,但是启动类加载只会加载rt.jar中的String。自定义的String不会被加载,因此报错“找不到或无法加载主类 basic.String”。这样可以防止恶意注入,例如注入擦除磁盘的操作,如果自定义String生效会导致磁盘数据丢失,影响数据安全。
如何打破双亲委派机制
- 使用自定义类加载
Tomcat为了实现隔离性和热替换,没有使用默认的类加载器,而是自己实现了类加载器: [ https://www.cnblogs.com/june0816/p/10090428.html ]