两种类别的类加载器(其实是4种)【重点】

https://www.jianshu.com/p/891c05b0ac05

CurrentClassLoader是当前方法所属的Class,加载这个Class的ClassLoader,这样有些别扭,其实就是如果A类中有方法调用,在方法调用中用到了B,那么在new的形式下,加载B的ClassLoader一定是加载A的ClassLoader而不是当前线程类加载器new操作时调用当前线程的类加载器,还是调用方的类加载器 文章予以证明)那么在加载B的时候,用来加载B的ClassLoader就是CurrentClassLoader。当然如果通过自定义加载器反射调用就是另外一回事情了
 
    @CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

 

Class.forName运作时,通过Reflection.getCallerClass(),能够获取是谁调用了Class.forName,这时Reflection.getClassClass() 返回的就是A.class,这样在通过指定ClassLoader来载入B

通过Reflection.getCallerClass()可以获取到调用Class.forName的类的ClassLoader注意不是forName所在类 Class.class.getClassloader,而是调用链上级

后者是saturn java 热加载(二)资源文件 spring & logback中第四类,前者是第一类,而Reflection所在类加载器即是第三类,第二类为当前线程类加载器

如果还是无法理解,就看回想一遍:JDBC注册原理与自定义类加载器解决com.cloudera.hive.jdbc41.HS2Driver的加载【重点】

归纳一下:

这个函数代码所在类加载器

调用这个函数的代码所在类加载器

当前线程类加载器

  A B.func() 当前线程
所在类加载器 1 2 3

 class B {  由myClassLoader2加载

  void func(){

    C c = new C();  那么此句究竟用那个类加载器来加载?

    c.func();

此时C的加载有3种选择

当前代码所在类加载器myClassLoader2;this.getClass().getClassLoader()

调用当前代码的代码(**调用B的func函数**)所在的类加载器myClassLoader1;Reflection.getCallerClass().getClassLoader()

以及当前现场的类加载器myClassLoader3;Thread.currentThread().getContextClassLoader()

  }

}

class A {  由myClassLoader1加载

  main() {

    Class cb = myClassLoader2.loadClass("B");

    **调用B的func函数**

  }

}

C c = new C();  那么此句究竟用那个类加载器来加载?

new操作时调用当前线程的类加载器,还是调用方的类加载器

new操作时调用当前线程的类加载器,还是调用方的类加载器 (二)

new操作时调用当前线程的类加载器,还是调用方的类加载器 (三)

三篇文章从实践来解答

如果一个JNDI的提供方,或者JAXP的提供方,他们的SPI是通过bootstrap加载的,但是他们的实现类必须通过应用ClassLoader甚至是更下层的ClassLoader来加载。那么在其初始化的过程中,需要考虑如果获取到部署了SPI实现的ClassLoader,而给出的方案是使用ContextClassLoader。

可以看出来CurrentClassLoader对用户来说是自动的,隐式的,而ContextClassLoader需要显示的使用,先进行设置然后再进行使用

原文地址:https://www.cnblogs.com/silyvin/p/12166103.html