🍈作者:王甜甜(dabing)
jdk 8 的类加载器
名称 | 加载哪的类 | 说明 |
---|---|---|
Bootstrap ClassLoader | JAVA_HOME/jre/lib | 无法直接访问 |
Extension ClassLoader | JAVA_HOME/jre/lib/ext | 上级为 Bootstrap,显示为 null |
Application ClassLoader | classpath | 上级为 Extension |
自定义类加载器 | 自定义 | 上级为 Application |
双亲委派机制
所谓的双亲委派,就是指优先委派上级类加载器进行加载,如果上级类加载器
- 能找到这个类,由上级加载,加载后该类也对下级加载器可见
- 找不到这个类,则下级类加载器才有资格执行加载
双亲委派的目的有两点
- 让上级类加载器中的类对下级共享(反之不行),即能让你的类能依赖到 jdk 提供的核心类
- 让类的加载有优先次序,保证核心类优先加载
1. 通过委派的方式,可以避免类的重复加载,当父加载器已经加载过某一个类时,子加载器就不会再重新加载这个类。
2. 通过双亲委派的方式,还保证了安全性。因为 Bootstrap ClassLoader 在加载的时候,只会加载 JAVA_HOME 中的 jar 包里面的类,如 java.lang.Integer,那么这个类是不会被随意替换的,除非有人跑到你的机器上, 破坏你的 JDK。那么,就可以避免有人自定义一个有破坏功能的 java.lang.Integer 被加载。这样可以有效的防止核心 Java API 被篡改。
双亲委派机制是在 classLoader 里的 loadclass 方法里实现的
# 1. Tomcat 如何打破双亲委派机制
如上图,上面的橙色部分还是和原来一样,采用双亲委派机制,而黄色部分是 tomcat 第一部分自定义的类加载器,这部分主要加载 tomcat 包中的类,这一部分依然采用的是双亲委派机制,而绿色部分是 tomcat 第二部分自定义类加载器,正是这一部分,打破了类的双亲委派机制。
我们来看看这三个类加载器的三个主要功能:
- commonClassLoader:tomcat 最基本的类加载器,加载路径中的 class 可以被 tomcat 容器本身和各个 webapp 访问;
- catalinaClassLoader:tomcat 容器中私有的类加载器,加载路径中的 class 对于 webapp 不可见的部分。
- sharedClassLoader:各个 webapps 共享的类加载器,加载路径中的 class 对于所有的 webapp 都可见,但是对于 tomcat 容器不可见。
- WebappClassLoader:各个 webapp 私有的类加载器,加载路径中的 class 只对当前 webapp 可见,比如加载 war 包里相关的类,每个 war 包应用都是自己的
WebappClassLoader:实现相互隔离,比如不同的 war 包应用引入了不同的 spring 版本,这样实现就能加载各自的 spring 版本。原文链接 : https://blog.csdn.net/weixin_40181736/article/details/125560640
# 2. 对双亲委派的误解
对双亲委派的误解
下面面试题的回答是错误的
错在哪了?
-
自己编写类加载器就能加载一个假冒的 java.lang.System 吗?答案是不行。
-
假设你自己的类加载器用双亲委派,那么优先由启动类加载器加载真正的 java.lang.System,自然不会加载假冒的
-
假设你自己的类加载器不用双亲委派,那么你的类加载器加载假冒的 java.lang.System 时,它需要先加载父类 java.lang.Object,而你没有用委派,找不到 java.lang.Object 所以加载会失败
-
以上也仅仅是假设。事实上操作你就会发现,自定义类加载器加载以 java. 打头的类时,会抛安全异常,在 jdk9 以上版本这些特殊包名都与模块进行了绑定,更连编译都过不了