> 文章列表 > Java双亲委派和类加载器

Java双亲委派和类加载器

Java双亲委派和类加载器

Java双亲委派和类加载

  • Java类生命周期
  • 主要内容
  • 类加载器的分类
    • Bootstrap ClassLoader
    • 非Bootstrap ClassLoader
      • Extension ClassLoader
      • Application ClassLoader
      • User ClassLoader
  • 类加载的命名空间
    • 问题提出
    • 双亲委派机制
    • 问题解答
  • 破坏双亲委派
    • 破坏双亲委派-第一次
    • 破坏双亲委派-第二次
  • 思考题

Java类生命周期

Java类加载分为以下几个步骤:
Java双亲委派和类加载器
只有加载步骤中的读取二进制流与初始化部分,能够被上层开发者,也就是大部分的Java程序员控制,而剩下的所有步骤,都是由JVM掌控,其中细节由JVM的开发人员处理,对上层开发者来说是个黑盒。

面向对象SOLID: 单一功能、开闭、里氏替换、接口隔离、依赖反转。

主要内容

Java双亲委派和类加载器

类加载器的分类

类加载器的分类属于JVM规范,属于一种抽象的概念。各个不同的JVM实现方式是不一定一样的。

JVM规范中类加载器分为两大类,分为启动类加载器非启动类加载器

本文主要关注HotSpot虚拟机。
Java双亲委派和类加载器

Bootstrap ClassLoader

Bootstrap ClassLoader是嵌套在JVM内部的,它主要用于加载java的核心类库。比如<JAVA_HOME>/lib下的jar包。或者是由启动参数来指定路径下的核心类库。

此外,为了安全性,Bootstrap ClassLoader只加载了包名在白名单中的文件。

非Bootstrap ClassLoader

Extension ClassLoader

是由内部类ext classloader来实现的。主要加载<JAVA_HOME>/lib/ext目录下或者是由系统变量指定的路径中的类库。

Extentsion ClassLoader希望加载的是Java API的拓展,是对Java类库的一些补充能力。

Application ClassLoader

是由内部类app classloader来实现的。主要加载classpath/java.class.path目录下或者是系统属性指定的路径中的类库。

Application ClassLoader希望加载的是上层程序员编写的一些代码以及一些第三方的类库。可以说程序员平时编写的代码都是由Application ClassLoader来加载的。

User ClassLoader

可以让用户获取任何地方的字节码,并对它们进行加载。这就印证了在Java类加载机制中,允许用户从各个渠道获取class文件的二进制流来进行加载的结论。

用户自定义的类加载器只需要继承java.lang.ClassLoader, 然后单独实现获取二进制流的逻辑。而后续的步骤必须让java.lang.ClassLoader中内置的逻辑来处理。用户无权进行重写和干涉。

类加载的命名空间

问题提出

1.不同的类加载器,除了读取二进制流的动作和范围不一样,后续的加载逻辑是否也不一样?
2. 遇到限定名一样的类,这么多类加载器会不会产生混乱?

JVM规范:每个类加载器都有属于自己的命名空间。

双亲委派机制

Java双亲委派和类加载器
在被动的情况下,当一个类加载器收到加载请求,他不会首先自己去加载,而是传递给自己的父亲加载器。

这样所有的类都会首先传递到最上层的Bootstrap ClassLoader,只有父亲加载器无法完成加载,那么儿子加载器才会自己去尝试加载。

无法加载:根据类的限定名,类的加载器没有在自己负责的加载路径中找到该类。

问题解答

  1. 不同的类加载器,除了读取二进制流的动作和范围不一样,后续的加载逻辑是否也不一样?
    我们认为除了Bootstrap ClassLoader,所有的非Bootstrap ClassLoader都继承了
    java.lang.ClassLoader,都由这个类的defineClass进行后续处理。

  2. 遇到限定名一样的类,这么多类加载器会不会产生混乱?
    越核心的类库被越上层的类加载器加载,而某限定名的类一旦被加载过了,被动情况下,就
    不会再加载相同限定名的类。这样,就能够有效避免混乱。

破坏双亲委派

但是双亲委派模型并不是一个具有强约束力的模型,因为他存在设计权限。在大部分被动情况下,他是生效并且好用的。但在一些情况可以被主动破坏。

破坏双亲委派-第一次

Java双亲委派和类加载器

破坏双亲委派-第二次

Java双亲委派和类加载器
上层的BootstrapClassLoader对下层的Application ClassLoader进行了委派加载。

思考题

能不能自己写一个限定名为java.lang.Stringl的类,并在程序中调用它?
如果在项目中单纯定义一个java.lang.String类,那么根据双亲委派原则会加载源码中的String,自定义类无法加载报错。如果使用自定义加载器去加载自定义的String类也不行,JDK源码好像限制了"java"开头的类,也就是保护核心源码的安全机制,防止乱改核心源码。

参考资料:【JVM】Java双亲委派、类加载器这块算是玩明白了