线程上下文类加载器的作用及实现

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);
        }

        //设置上下文类加载器,这个后面会详细说
        Thread.currentThread().setContextClassLoader(this.loader);

       //删除了一些安全方面的代码
       //...
}

//设置上下文类加载器,这个后面会详细说
Thread.currentThread().setContextClassLoader(this.loader);

补充一个代码段:

private static Connection getConnection(
        String url, java.util.Properties info, Class caller) throws SQLException {
        //获取调用者的类加载器
        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
        synchronized(DriverManager.class) {
            //如果为null,则使用上下文类加载器
            //这里是重点,什么时候类加载器才会为null? 当然就是由根类加载器加载的类了
            if (callerCL == null) {
                callerCL = Thread.currentThread().getContextClassLoader();
            }
        }

        //...省略

        for(DriverInfo aDriver : registeredDrivers) {
            //使用上下文类加载器去加载驱动
            if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    //如果加载成功,则进行连接
                    Connection con = aDriver.driver.connect(url, info);
                    //...
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }
            } 
            //...
        }
    }

重点说明:
为什么上下文类加载器就可以加载到数据库驱动呢?回到上面一开始Launcher初始化类加载器的源码,我们发现原来所谓的上下文类加载器本质上就是应用类加载器,有没有豁然开朗的感觉?上下文类加载器只是为了解决类的逆向访问提出来的一个概念,并不是一个全新的类加载器,它本质上就是应用类加载器。

链接:https://www.jianshu.com/p/a6ba4f152968

转载:https://blog.csdn.net/zhoudaxia/article/details/35897057
为什么用线程上下文?因为SPI接口一般在核心库里,有引导类加载器(BootStrap)加载,然后具体实现是在系统类加载器(APP)里面,引导类只加载核心库里的,又不能代理给系统类加载器,因为引导类是系统类的祖先

这个更好理解:https://blog.csdn.net/javazejian/article/details/73413292

但是我有个疑问:
线程上下文类加载器的作用及实现_第1张图片

可以这样理解吗:
我要新建一个对象,那返回的应该是调用new object()方法时候线程(creator)的加载器,(这时候应该是app加载器),然后一路向上走到了bootstrap加载器,然后发现这个类是在核心jar包里的,如常见的 SPI 有 JDBC、JNDI等,这些 SPI 的接口属于 Java 核心库,一般存在rt.jar包中,由Bootstrap类加载器加载。但具体的方法在app加载器里。这时候系统会判断(比如遍历寻找),如果这个这个方法属于核心jar包,那么就调用这个线程,获取执行new Object的这个线程的加载器(比如app加载器),去加载具体的实现类。没设置的话默认是系统加载器,也就是app.

那么dubbo的SPI为什么需要用这种方式??
jar包是放在classpath底下的,也就是属于app加载器,那里面为什么要用线程类加载器来加载呢??看到一个回答但不知道对不对:
线程上下文类加载器的作用及实现_第2张图片

你可能感兴趣的:(基础包)