目录
一、类加载器
类加载器分类
启动类加载器
扩展类加载器
应用类加载器
二、双亲委派机制
双亲委派模型
模块下的类加载器
启动类加载器负责加载的模块
平台类加载器负责加载的模块
应用程序类加载器负责加载的模块
说到双亲委派机制,首先你要了解,什么是类加载器,下面就先简单说一下类加载器,后面在对双亲委派机制进行了解。
一、类加载器
java虚拟机设计团队有意将类加载阶段中“通过一个类的全限定名来获取描述该类的二进制字节流”这个动作放到java虚拟机外部去实现,以便于让应用程序自己决定如何去获取所需的类。实现这个动作的代码称作为“类加载器(Class Loader)”
------《深入理解JAVA虚拟机》
类加载器分类
站在java虚拟机的角度看,JVM支持两种加载器,分别为引导类加载器(BootstrapClassLoader)和自定义类加载器。从概念上来说自定义加载器一般是程序中由开发人员定义的一类加载器,然而java虚拟机规范中并没有这样定义,而是将所有派生于抽象类ClassLoader的类加载器都划分为自定义加载器。
一般来说在java8以及以前的版本都会用到如下三种加载器:
- 启动类加载器(Bootstrap Class Loader)
- 扩展类加载器(Extension Class Loader)
- 应用类加载器(Application Class Loader)
启动类加载器
该加载器使用C++实现(不会继承ClassLoader),是虚拟机自身的一部分。该类加载器主要是负责加载存放在JAVA_HOME\lib目录,或者被-Xbootclasspath参数指定路径存放的,并且是java虚拟机能识别的类库加载到虚拟机内存中。(eg:主要是加载java的核心类库,即加载lib目录下的所有class)
扩展类加载器
这个类加载器主要是负责加载JAVA_HOME\lib\ext目录中,或者被java.ext.dirs系统变量所指定的路径中所有类库
应用类加载器
这个类的加载器是由sun.misc.Launcher$AppClassLoader来实现,因为该加载器是ClassLoader类中的getSystemClassLoader()方法的返回值,所以一般也称为该加载器为系统类加载器。该加载器主要是加载用户类路径上所有的类库,如果应用程序中没有定义过自己的类加载器,一般情况下这个就是程序的默认加载器。
介绍完了加载器,下面就是本文章的重点
二、双亲委派机制
双亲委派模型(1.8以及之前版本)
先了解一下双亲委派机制的过程:
如果一个类加载器收到了类加载请求,它首先不会自动去尝试加载这个类,而是把这个类委托给父类加载器去完成,每一层依次这样,因此所有的加载请求都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成该加载请求(找不到所需的类)时,这个时候子加载器才会尝试自己去加载,这个过程就是双亲委派机制!
大概的流程如下图1所示:
双亲委派机制有什么优点:
1.避免了类的重复加载
2.保护了程序的安全性,防止核心的API被修改
模块下的类加载器(1.9以及之后版本)
但是在java9以及以后的版本中,为了模块化系统的顺利实施,模块下的类加载器主要有几个变动:
1.扩展类加载器(Extension Class Loader)被平台类加载器(Platform ClassLoader)取代(java9中整个JDK都是基于了模块化的构建,原来的rt.jar和tools.jar都被拆分了数十个JMOD文件)。因为java类库可以满足扩展的需求并且能随时组合构建出程序运行的jre,所以取消了JAVA_HOME\lib\ext和JAVA_HOME\jre目录
2.平台类加载器和应用程序类加载器都不在派生自java.net.URLClassLoader。现在启动类加载器、平台类加载器、应用程序类加载器全都继承于jdk.internal.loader.BuiltinClassLoader,在BuiltinClassLoader中实现了新的模块化架构下类如何从模块中加载的逻辑,以及模块中资源可访问性的处理。
就是说平台以及应用程序类加载器收到类的加载请求的时候,在委派给父类加载器家在之前,要先判断该类是否归属于摸一个系统模块,如果可以找到这样的归属关系,就要优先委派给负责那个模块的加载器完成加载。如下图2:
各个类加载器的归属关系如下:
启动类加载器负责加载的模块
平台类加载器负责加载的模块
应用程序类加载器负责加载的模块
参考文章:《深入理解JAVA虚拟机》第三版 -周志明