Java 类加载体系之 ClassLoader 双亲委托机制

java 是一种类型安全的语言,它有四类称为安全沙箱机制的安全机制来保证语言的安全性,这四类安全沙箱分别是:

  • 类加载体系
  • .class文件检验器
  • 内置于java虚拟机的安全特性
  • 安全管理器及javaAPI

类的加载体系如下

java 程序中的 .java 文件编译完会生成 .class 文件,而 .class 文件就是通过被称为类加载器的 ClassLoader加载的,而 ClassLoder 在加载过程中会使用“双亲委派机制”来加载 .class 文件,先上图:

BootStrapClassLoader :启 动 类 加 载 器 ,该ClassLoader 是 jvm 在 启 动 时 创 建 的 ,用 于 加载$JAVA_HOME$/jre/lib 下面的类库(或者通过参数-Xbootclasspath 指定)。由于启动类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不能直接通过引用进行操作。

ExtClassLoader:扩展类加载器,该 ClassLoader 是在 sun.misc.Launcher 里作为一个内部类 ExtClassLoader 定义的(即 sun.misc.Launcher$ExtClassLoader),ExtClassLoader 会加载 $JAVA_HOME/jre/lib/ext 下的类库(或者通过参数-Djava.ext.dirs 指定)。

AppClassLoader:应用程序类加载器,该 ClassLoader 同样是在 sun.misc.Launcher 里作为一个内部AppClassLoader 定义的(即 sun.misc.Launcher$AppClassLoader),AppClassLoader 会加载 java 环境变量 CLASSPATH 所指定的路径 下的类库,而 CLASSPATH 所指定的 路 径 可 以 通 过System.getProperty("java.class.path")获取;当然,该变量也可以覆盖,可以使用参数-cp,例如:java -cp 路径 (可以指定要执行的 class 目录)。

CustomClassLoader:自定义类加载器,该 ClassLoader 是指我们自定义的 ClassLoader,比如 tomcatStandardClassLoader 属于这一类;当然,大部分情况下使用 AppClassLoader 就足够了。

前面谈到了 ClassLoader 的几类加载器,而 ClassLoader 使用双亲委派机制来加载 class 文件的。ClassLoader的双亲委派机制是这样的(这里先忽略掉自定义类加载器 CustomClassLoader):

1)当 AppClassLoader 加载一个 class 时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器 ExtClassLoader 去完成。

2)当 ExtClassLoader 加载一个 class 时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader 去完成。

3)如果 BootStrapClassLoader 加载失败(例如在$JAVA_HOME$/jre/lib 里未查找到该 class),会使用ExtClassLoader 来尝试加载;

4)若 ExtClassLoader 也加载失败,则会使用 AppClassLoader 来加载,如果 AppClassLoader 也加载失败,则会报出异常 ClassNotFoundException。

下面贴下 ClassLoader 的 loadClass(String name, boolean resolve)的源码:

1.protected synchronized Class<?> loadClass(String name, boolean resolve)
2.  throws  ClassNotFoundException  {
3. //  首先找缓存是否有 class
4. Class  c  =  findLoadedClass(name);
5. if  (c  ==  null)  {
6. //没有判断有没有父类
7. try  {
8. if  (parent  !=  null)  {
9. //有的话,用父类递归获取 class
10. c = parent.loadClass(name, false);
11. } else {
12. //没有父类。通过这个方法来加载
13. c = findBootstrapClassOrNull(name);
14. }
15. } catch (ClassNotFoundException e) {
16. // ClassNotFoundException thrown if class not found
17. // from the non-null parent class loader
18. }
19. if (c == null) {
20. //  如果还是没有找到,调用 findClass(name)去找这个类
21. c = findClass(name);
22. }
23. }
24. if (resolve) {
25. resolveClass(c);
26. }
27. return c;
28.  }

代码很明朗:首先找缓存(findLoadedClass),没有的话就判断有没有 parent,有的话就用 parent 来递归的 loadClass,然而 ExtClassLoader 并没有设置 parent,则会通过 findBootstrapClassOrNull 来加载 class,而findBootstrapClassOrNull 则会通过 JNI 方法”private native Class findBootstrapClass(String name)“来使用 BootStrapClassLoader 来加载 class。

然后如果 parent 未找到 class,则会调用 findClass 来加载 class,findClass 是一个 protected 的空方法,可以覆盖它以便自定义 class 加载过程。另 外 ,虽 然 ClassLoader 加载类是使用 loadClass 方法 ,但 是 鼓 励 用 ClassLoader 的 子 类 重 写 findClass(String),而不是重写 loadClass,这样就不会覆盖了类加载默认的双亲委派机制。

双亲委派托机制为什么安全

举个例子,ClassLoader 加载的 class 文件来源很多,比如编译器编译生成的 class、或者网络下载的字节码。而一些来源的 class 文件是不可靠的,比如我可以自定义一个 java.lang.Integer 类来覆盖 jdk 中默认的 Integer 类,例如下面这样:

1. package java.lang;
2. public class Integer {
3.   public Integer(int value) {
4.  System.exit(0);
5. }
6. }

初始化这个 Integer 的构造器是会退出 JVM,破坏应用程序的正常进行,如果使用双亲委派机制的话该 Integer 类永远不会被调用,以为委托 BootStrapClassLoader 加载后会加载 JDK 中的 Integer 类而不会加载自定义的这个,可以看下下面这测试个用例:

1.public static void main(String...  args) {
2. Integer i = new Integer(1);
3. System.err.println(i);
4.}

执行时 JVM 并未在 new Integer(1)时退出,说明未使用自定义的 Integer,于是就保证了安全性。

Java 类加载体系之 ClassLoader 双亲委托机制的更多相关文章

  1. java安全沙箱(一)之ClassLoader双亲委派机制

    java是一种类型安全的语言,它有四类称为安全沙箱机制的安全机制来保证语言的安全性,这四类安全沙箱分别是: 类加载体系 .class文件检验器 内置于Java虚拟机(及语言)的安全特性 安全管理器及J ...

  2. classLoader双亲委托与类加载隔离

    虽然前面把class文件的产生到加载使用流程说了一遍,但是还是想具体看看classLoader的双亲委托具体是如何运行的,有什么利弊. 还有想看看不同类加载器的不同命名空间带来那些好处和实际有那些应用 ...

  3. JAVA基础|从Class.forName初始化数据库到SPI破坏双亲委托机制

    代码托管在:https://github.com/fabe2ry/classloaderDemo 初始化数据库 如果你写过操作数据库的程序的话,可能会注意,有的代码会在程序的开头,有Class.for ...

  4. JVM 类加载器的双亲委托机制

    1.类加载器的层次结构 在双亲委托机制中,各个加载器按照父子关系形成了树形结构(逻辑意义),除了根加载器之外,其余的类加载器都有且只有一个父加载器. public class MyTest13 { p ...

  5. Java基础-类加载机制与自定义类Java类加载器(ClassLoader)

    Java基础-类加载机制与自定义类Java类加载器(ClassLoader) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 关于类加载器的概念和分类我就不再废话了,因为我在之前的笔 ...

  6. 破坏双亲委托机制的一些情况---Tomcat和JDBC,破坏后的安全问题

    采用双亲委托机制的原因 类加载器就是将字节码搬进jvm方法区的组件.我们知道,JVM识别加载进来的类是通过类加载器+类全名完成的,也就是说同一个类由不同类加载器加载进去的话就会被视为不同的类.jdk提 ...

  7. 【JVM学习笔记】双亲委托机制存在的意义

    1.可以确保Java核心库的类型安全:所有的Java应用都至少会引用java.lang.Object类,也就是说在运行期,java.lang.Object这个类会被加载到Java虚拟机:如果用户自定义 ...

  8. ClassLoader类加载器 & Java类加载机制 & 破坏双亲委托机制

    ClassLoader类加载器 Java 中的类加载器大致可以分成两类: 一类是系统提供的: 引导类加载器(Bootstrap classloader):它用来加载 Java 的核心库(如rt.jar ...

  9. java的类加载器体系结构和双亲委派机制

    类加载器将字节码文件加载到内存中,同时在方法区中生成对应的java.land.class对象  作为外部访问方法区的入口. 类加载器的层次结构: 引导类加载器<-------------扩展类加 ...

随机推荐

  1. 使用vue-cli脚手架安装和webpack-simple模板项目生成

    Vue-cli 是一个官方发布 vue.js 项目脚手架,使用 vue-cli 可以快速创建 vue 项目. GitHub地址是:https://github.com/vuejs/vue-cli 一. ...

  2. transient关键字与序列化、反序列化

    transient,中文翻译是短暂的,和对象序列化.反序列化有关. 一个类只要实现了Serializable接口,则该类实例就可以序列化,具体来说实例的每个非静态成员变量都会序列化.注意是非静态成员变 ...

  3. Linux虚拟机无法通过宿主机上网

    解决方法 1.Windows: 确保相关服务已经启动 2.Linux: 确保相关服务已经启动 1) 确认Linux的IP地址和Windows在同一个网段: 若Windows给虚拟机分配的IP地址如下: ...

  4. springboot 启动的java进程默默终止

    首先说明这是一个灵异事件......... 场景1 :把之前用map实现的缓存用Redis重构,高高兴兴上线更新,10 分钟后,老板告诉我,项目停了,what ??? 像我这么帅气,英俊,聪明的人,更 ...

  5. Bootloader 跳转到 RT-Thread 或 FreeRTOS(基于 STM32)

    Bootloader 跳转到 RT-Thread 或 FreeRTOS(基于 STM32) 作者:猾蚁 QQ:7376220一.Bootloader 程序1. 准备好升级程序项目,可以使用 STM32 ...

  6. RTT之POSIX

    POSIX:可移植操作系统接口,是一个标准. 创建线程:如果线程创建成功,线程立刻进入就绪态,参与系统的调度,如果线程创建失败,则会释放之前线程占有的资源int pthread_create (pth ...

  7. 连接虚机中的mysql服务

    1:修改mysql库中的user表的root用户的host值为% 2:授权:在mysql命令中执行 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFI ...

  8. Spring boot-(2) Spring Boot使用

    1. 构建系统 (1) 使用maven构建 1) 从Starter Parent继承 在项目中配置继承spring-boot-starter-parent,可以进行如下设置: <!-- Inhe ...

  9. Fedora 安装 phpMyAdmin(可能只有自己看得懂)

    yum groupinstall "Development Tools" yum install php-mysqli php-mbstring php-mcrypt yum in ...

  10. Qt 学习

    Qt 学习 C++ 模版 QObject 提供一个十分有用的 api,T findChild(QString, Qt::FindChildOptions),这个函数接收一个模版参数,返回模版参数的类型 ...