🍈作者:王甜甜(dabing)

jdk 8 的类加载器

名称 加载哪的类 说明
Bootstrap ClassLoader JAVA_HOME/jre/lib 无法直接访问
Extension ClassLoader JAVA_HOME/jre/lib/ext 上级为 Bootstrap,显示为 null
Application ClassLoader classpath 上级为 Extension
自定义类加载器 自定义 上级为 Application

双亲委派机制

所谓的双亲委派,就是指优先委派上级类加载器进行加载,如果上级类加载器

  • 能找到这个类,由上级加载,加载后该类也对下级加载器可见
  • 找不到这个类,则下级类加载器才有资格执行加载

双亲委派的目的有两点

  1. 让上级类加载器中的类对下级共享(反之不行),即能让你的类能依赖到 jdk 提供的核心类
  2. 让类的加载有优先次序,保证核心类优先加载

1. 通过委派的方式,可以避免类的重复加载,当父加载器已经加载过某一个类时,子加载器就不会再重新加载这个类。
2. 通过双亲委派的方式,还保证了安全性。因为 Bootstrap ClassLoader 在加载的时候,只会加载 JAVA_HOME 中的 jar 包里面的类,如 java.lang.Integer,那么这个类是不会被随意替换的,除非有人跑到你的机器上, 破坏你的 JDK。那么,就可以避免有人自定义一个有破坏功能的 java.lang.Integer 被加载。这样可以有效的防止核心 Java API 被篡改。
双亲委派机制是在 classLoader 里的 loadclass 方法里实现的

# 1. Tomcat 如何打破双亲委派机制

img

如上图,上面的橙色部分还是和原来一样,采用双亲委派机制,而黄色部分是 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. 对双亲委派的误解

对双亲委派的误解

下面面试题的回答是错误的

image-20210901110910016

错在哪了?

  • 自己编写类加载器就能加载一个假冒的 java.lang.System 吗?答案是不行。

  • 假设你自己的类加载器用双亲委派,那么优先由启动类加载器加载真正的 java.lang.System,自然不会加载假冒的

  • 假设你自己的类加载器不用双亲委派,那么你的类加载器加载假冒的 java.lang.System 时,它需要先加载父类 java.lang.Object,而你没有用委派,找不到 java.lang.Object 所以加载会失败

  • 以上也仅仅是假设。事实上操作你就会发现,自定义类加载器加载以 java. 打头的类时,会抛安全异常,在 jdk9 以上版本这些特殊包名都与模块进行了绑定,更连编译都过不了

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Dabing-He 微信支付

微信支付