线程上下文类加载器(Thread Context ClassLoader)
线程上下文件类加载器(Thread Context ClassLoader)
//设置线程上下文类加载器
通过java.lang.Thread类的setContextClassLoader(ClassLoader cl)方法来设置;
如果创建线程时还未设置上下文类加载器,那么当前线程将会从父线程中继承一个上下文类加载器,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认就是应用程序类加载器。
线程上下文类加载器如何破坏双亲委派模型
https://www.cnblogs.com/liuligang/p/10519771.html
Java提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。
这些 SPI 的接口由 Java 核心库来提供,而SPI接口中的代码经常需要加载具体的实现类;
这些实现类由 独立厂商 提供,位于 classpath下;
SPI的接口是Java核心库的一部分,是由启动类加载器(Bootstrap Classloader)来加载的;SPI的实现类是由系统类加载器(System ClassLoader)来加载的。引导类加载器是无法找到 SPI 的实现类的,因为依照双亲委派模型,BootstrapClassloader无法委派AppClassLoader来加载类。
在 SPI 接口的代码中直接使用线程上下文类加载器,就可以成功的加载到 SPI 实现的类。
sun.misc.Launcher
https://blog.csdn.net/chaofanwei2/article/details/51335278
https://blog.csdn.net/x_iya/article/details/104459985
https://blog.csdn.net/zhouhao88410234/article/details/92708723
// sun.misc.Launcher 部分源码
static class AppClassLoader extends URLClassLoader {
……
}
static class ExtClassLoader extends URLClassLoader {
……
}
“系统类加载器AppClassLoader”、“扩展类加载器ExtClassLoader”都是位于 sun.misc.Launcher。但是它们的访问修饰符(default)导致外界无法直接访问这个加载器。
//sun.misc.Launcher部分源码
private static Launcher launcher = new Launcher(); // 注意,static修饰;
public Launcher() {
Launcher.ExtClassLoader var1;
try {
// 构建 扩展类加载器
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
// 构建 系统类加载器
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
}
//设置线程 上下文类加载器 ,this.loader = AppClassLoader;
Thread.currentThread().setContextClassLoader(this.loader);
...
}
可以看到Launcher类初始化时,先初始化了个ExtClassLoader,然后又初始化了个AppClassLoader,然后把ExtClassLoader作为AppClassLoader的父loader,以及 设置 线程上下文类加载器。
Launcher类是由’启动类加载器’加载的,即 启动类加载器加载sun.misc.Launcher类,Launcher加载扩展类加载器、系统类加载器 以及 设置 线程上下文类加载器;