JVM类加载器!

Bootstrap引导类加载器

引导类加载器也被称为启动类加载器或根类加载器

  • BootstrapClassLoader

引导类加载器使用C++语言实现,是JVM自身的一部分

  • 主要负责将<JAVA_HOME>\lib路径下的核心类库
  • -Xbootclasspath参数指定的路径下的jar包加载到内存中。

Extension拓展类加载器

位于HotSpot源码目录中的sun.misc.Launcher$ExtClassLoader位置。

它主要负责加载<JAVA_HOME>\lib\ext目录下

  • 或者由系统变量-Djava.ext.dir指定位路径中的类库。

Application系统类加载器

位于HotSpot源码目录中的sun.misc.Launcher$AppClassLoader位置。

它负责加载系统类路径java -classpath

  • -D java.class.path指定路径下的类库,也就是classpath路径。

该类加载器是程序的默认类加载器

  • 可以通过ClassLoader.getSystemClassLoader()方法可以直接获取到它。

自定义类加载器

如果需要自定义类加载器,只需要继承ClassLoader

  • 但继承ClassLoader需要自己重写findClass()方法并编写加载逻辑

在自定义ClassLoader的子类时,会有两种做法:

  • 重写loadClass()方法

  • 重写findClass()方法

loadClass()最终调用的还是findClass()方法

  • 如果想打破双亲委派模型,那么就重写整个loadClass方法

  • 如果不想打破双亲委派模型,那么只需要重写findClass方法

线程上下文类加载器

很多服务提供者接口(Service Provider Interface,SPI),这些接口允许第三方为它们提供实现

  • 如常见的SPIJDBC、JNDI

这些SPI的接口属于Java核心库,一般存在rt.jar包中

  • 由启动类加载器(Bootstrap)加载
  • SPI的第三方实现代码则是作为Java应用所依赖的jar包被存放在classpath路径下。

由于SPI接口中的代码需要加载第三方实现类并调用其相关函数

  • SPI的核心接口类是由启动类加载器(Bootstrap)加载的,Bootstrap加载器无法直接加载SPI的实现类。

SPI提供了一种动态的服务发现机制(约定),只要第三方在编写实现类时

  • 在工程内新建一个META-INF/services/目录并在该目录下创建一个与服务接口名称同名的文件
  • 那么在程序启动的时候,就会根据约定去找到所有符合规范的实现类
    • 然后交给线程上下文类加载器进行加载处理。

线程的上下文类加载器默认设置的就是系统类加载器(System)。

image-20231026171802543

JDK1.8和1.9中类加载器有哪些不同

JDK 1.9 引入 Jigsaw 模块化系统(Project Jigsaw),对类加载器进行了调整。

JDK 1.8 JDK 1.9 及之后 变化
扩展类加载器(Extension ClassLoader) 平台类加载器(Platform ClassLoader) 负责加载 JDK 模块化系统中的非核心模块
应用类加载器(Application ClassLoader) 应用类加载器(Application ClassLoader) 负责加载应用程序的 classpath

JDK 1.9 类加载器结构:

1
2
3
4
5
6
Bootstrap ClassLoader
├── Platform ClassLoader (JDK 9+ 新增)
│ ├── 加载 JDK 平台模块(如 java.sql)
├── Application ClassLoader
├── 加载 classpath 目录
├── 自定义类加载器(User-defined ClassLoader)
JDK 版本 主要类加载器 变化
JDK 1.8 及之前 Bootstrap、Extension、Application 使用 Extension ClassLoader 加载 lib/ext
JDK 1.9 及之后 Bootstrap、Platform、Application Extension ClassLoaderPlatform ClassLoader 取代