两种类别的类加载器(其实是4种)【重点】
https://www.jianshu.com/p/891c05b0ac05
@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操作时调用当前线程的类加载器,还是调用方的类加载器 (三)
三篇文章从实践来解答
可以看出来CurrentClassLoader对用户来说是自动的,隐式的,而ContextClassLoader需要显示的使用,先进行设置然后再进行使用。