jvm -- 白话类加载器
永远固定的类加载器
根类加载器 (C++编写 ,是根类加载器 ,是没有指定父 类 加载器的 类加载器的父类)
ExtClassLoader(扩展类加载器 ,默认没有指定 父类加载器 )
AppClassLoader(应用类加载器 ,指定类加载器没 ExtClassLoader)
一般情况下,我们说 的结构
AppClassLoader的 父类加载器 为 ExtClassLoader ,是构造函数中指定的,使用组合表示 的类加载器
对于ExtClassLoader,构造函数
public ExtClassLoader(File[] var1) throws IOException {
super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
}
其中,设置null为 父类加载器
但是我们通常认为其 父类加载器 为 根类加载器,是因为在 LoadClass时,或默认选择 父类加载器进行加载,而 对于父类为空的情况,使用 根类加载其进行加载(findBootstrapClassOrNull就是,根类加载器 也被称为BootstrapClassLoader)
getSystemClassloader (系统类加载器),再没有使用java.system.class.loader进行指定的时候,就是AppClassLoader ,参看 https://www.cnblogs.com/sxrtb/p/14611395.html
public static ClassLoader getSystemClassLoader() { initSystemClassLoader(); if (scl == null) { return null; } SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkClassLoaderPermission(scl, Reflection.getCallerClass()); } return scl; }
private static synchronized void initSystemClassLoader() { if (!sclSet) { if (scl != null) throw new IllegalStateException("recursive invocation"); sun.misc.Launcher l = sun.misc.Launcher.getLauncher(); if (l != null) { Throwable oops = null; scl = l.getClassLoader(); try { scl = AccessController.doPrivileged( new SystemClassLoaderAction(scl));//要是没有java.system.class.loader设置,则AppClassLoader为系统类加载器 } catch (PrivilegedActionException pae) { oops = pae.getCause(); if (oops instanceof InvocationTargetException) { oops = oops.getCause(); } } if (oops != null) { if (oops instanceof Error) { throw (Error) oops; } else { // wrap the exception throw new Error(oops); } } } sclSet = true; } }
class SystemClassLoaderAction implements PrivilegedExceptionAction<ClassLoader> { private ClassLoader parent; SystemClassLoaderAction(ClassLoader parent) { this.parent = parent; } public ClassLoader run() throws Exception { String cls = System.getProperty("java.system.class.loader"); if (cls == null) { return parent; //由InitSystemClassLoader可知,若此处返回 , 则值为AppClassLoader } Constructor<?> ctor = Class.forName(cls, true, parent) .getDeclaredConstructor(new Class<?>[] { ClassLoader.class }); ClassLoader sys = (ClassLoader) ctor.newInstance( new Object[] { parent }); // java.system.class.loader必须有一个接受一个ClassLoader参数的构造函数 ,将AppClassLoader传入进去 Thread.currentThread().setContextClassLoader(sys);//设置线程上下文类加载器 return sys; } }
指定了 java.system.class.loader的情况下 ,一般设置 AppClassLoader为 其父类加载器 (也就是说,可以 不 设置 AppClassLoader 为 系统类加载器的 父类 加载器)
具体还是上面的代码,最有的的一段
Thread.currentThread().getContextClassLoader() (线程上下文类加载器)
这个的默认设置有两处
由于此处调用没办法调式(反正我是没有调试出来),我个人的理解是
在没有设置 java.system.class.loader 的情况下,AppClassLoader为 线程上下文类加载器
在设置 java.system.class.loader 的情况下,线程上下文类加载器 为 System.class.loader (系统类加载器)
自定义类加载器
若自定义类加载器设置父类加载器为null ,参考https://www.cnblogs.com/sxrtb/p/14594324.html 实际上还是还是可以访问rt.jar(由根类加载器加载的类,而由于命名空间限制,类加载器只能访问自己加载的类 及其 父类加载器加载的 类),则其实根 类加载器可以 理解为是它的 父类加载器 (同ExtClassLoader设置父类加载器为 null 的 情况相同)
若构造函数中 使用super(),本质调用
protected ClassLoader() {//使用 系统类 加载器 创建ClassLoader this(checkCreateClassLoader(), getSystemClassLoader()); }
即,设置SystemClassLoader为其 父类加载器
当然,此处可以根据 设计需要,将另外一个自定义类加载器 设置为 其 父类加载器
问,我们自己写的程序到底是由那个类加载器进行?如运行 CacheClassLoaderTest2
系统类加载器。(具体验证,将自定义类加载器设置称系统类加载器,将自定义类加载器的父加载器设置成null,让自定义类加载器来加载 CacheClassLoaderTest2 ,输出结果肯定是 自定义类加载器。注意:此时原本由AppClassLoader加载的,但此时就没有用AppClassLoader加载,而是自定义的系统类加载器加载的。所以,我们自己写的程序,实质 使用系统类加载器 进行加载)
public class CacheClassLoaderTest2 { public static void main(String[] args) { System.out.println(CacheClassLoaderTest2.class.getClassLoader()); } }
posted on 2021-04-02 18:53 xingshouzhan 阅读(58) 评论(0) 编辑 收藏 举报