基础知识点
知识点1: 每个ClassLoader都只能加载自己所绑定目录下的资源;
知识点2: 加载资源时的ClassLoader可以有多种选择:
1. 系统类加载器SystemClassLoader,可通过ClassLoader.getSystemClassLoader()获得;
2. 当前ClassLoader:加载了当前类的ClassLoader;
3. 线程上下文类加载器ContextClassLoader:Thread.currentThread().getContextClassLoader();
4. 自定义类加载器;
ContextClassLoader作用
加载类或资源的手段之一,只不过在一些场景下成为了唯一可选手段,从而显得特别重要,比如在JDK的SPI接口中加载SPI实现类,插件的加载等,下面以JDBC驱动的加载过程为例进行说明。
JDBC驱动的加载过程
应用程序加载驱动的方式如下:
- 调用Class.forName()加载mysql的驱动,由于调用类SpiTest在classpath路径上,因此使用使用SystemClassLoader加载类”com.mysql.jdbc.Driver”;
- 加载过程中会执行static语句块,将驱动实例注册到DriverManager中,此时会涉及到DriverManager类的加载,如下图所示:
- DriverManager类的加载也会执行static语句块,逻辑是使用ServiceLoader机制加载各种JDBC驱动,如下图所示:
- 最终调用ServiceLoader.load()方法加载驱动,此时就只能使用ContextClassLoader进行加载,如下图所示:
原因是:当前类加载器(DriverManager类的加载器)为启动类加载器,只能加载JDK核心类,当然也无法在JDK中创建自定义的ClassLoader,因此可选的ClassLoader只有两种,即SystemClassLoader和ContextClassLoader。但是SystemClassLoader只能加载classpath路径下的驱动,有局限性。ContextClassLoader没有局限性,可以在应用程序中将其设为任意ClassLoader,加载任意目录下的类和资源,如下图所示: