我们知道我们可以覆盖 System类加载器:
java -Djava.system.class.loader=com.test.MyClassLoader xxx
那么,既然com.test.MyClassLoader
它本身就是一个类,那么它是由谁来加载的呢?
我们如何获得这个“元”类加载器的类文件?
我们知道我们可以覆盖 System类加载器:
java -Djava.system.class.loader=com.test.MyClassLoader xxx
那么,既然com.test.MyClassLoader
它本身就是一个类,那么它是由谁来加载的呢?
我们如何获得这个“元”类加载器的类文件?
Bootstrap classloader
是 all 的父级,classloaders
并在 JRE(rt.jar 和 i18n.jar)的 lib 目录中加载标准 JDK 类。所有 java.* 类都由 this 加载classloader
。
Extensions Classloader
是 Bootstrap 类加载器的直接子级。这个类加载器加载 JRE 的 lib\ext 目录中的类。
System-Classpath classloader
是 Extensions 类加载器的直接子级。CLASSPATH
它加载环境变量指定的类和jar
您可以尝试通过“java.system.class.loader”属性注入您的自定义类加载器(参见ClassLoader#getSystemClassLoader)。
Default System class loader
是 MyClassLoader 实例的父级,
来自 Javadoc 的ClassLoader.getSystemClassLoader
:
如果在首次调用此方法时定义了系统属性“java.system.class.loader”,则该属性的值将被视为将作为系统类加载器返回的类的名称。该类使用默认的系统类加载器加载,并且必须定义一个公共构造函数,该构造函数采用一个 ClassLoader 类型的参数,该参数用作委托父级。
默认系统类加载器本身特定于 JVM 实现。
§ ..该属性的值被视为将作为系统类加载器返回的类的名称。该类是使用默认的系统类加载器加载的..
..因此,如果您的类加载器将 X 替换为系统类加载器,那么您的类加载器的父级将是 X,即默认的系统类加载器。
(X 的类型类似于sun.misc.Launcher$AppClassLoader
。)
更多信息可在docs.oracle.com - Java Launcher 如何查找类:
Java 启动器 java 启动 Java 虚拟机。虚拟机按以下顺序搜索和加载类:
引导类- 组成 Java 平台的类,包括 rt.jar 中的类和其他几个重要的 jar 文件。
扩展类- 使用 Java 扩展机制的类。这些被捆绑为位于扩展目录中的 .jar 文件。
用户类- 由开发人员和第三方定义的不利用扩展机制的类。您可以使用命令行上的 -classpath 选项或使用 CLASSPATH 环境变量来识别这些类的位置。
我们可以证明 X 确实是我们的父级Classloader
:
/** run with -Djava.system.class.loader=MyCL to use this classloader */
public class MyCL extends ClassLoader {
public MyCL(ClassLoader parent) { // this constructor must be public, else IllegalAccessException
super(parent);
}
}
这是我们的主要代码:
public class Main {
public static void main(String args[]) {
System.out.println("getSystemClassLoader(): " + ClassLoader.getSystemClassLoader());
ClassLoader cl = MyCL.class.getClassLoader();
System.out.println("Classloader of MyCL: " + cl);
Class type_of_cl = cl.getClass();
System.out.println("..and its type: " + type_of_cl);
ClassLoader cl_of_cl = class_of_cl.getClassLoader();
System.out.println("Classloader of (Classloader of MyCL): " + cl_of_cl);
}
}
这是使用命令运行时的输出(在我的系统上)java -Djava.system.class.loader=MyCL Main
(参见Eclipse run config):
getSystemClassLoader(): MyCL@1888759 MyCL
的类加载器:sun.misc.Launcher$AppClassLoader@7fdcde
..及其类型:sun.misc.Launcher$AppClassLoader
类的类加载器(MyCL 的类加载器):null
我们可以看到MyCL
的类加载器是sun.misc.Launcher$AppClassLoader
,这是系统默认的类加载器。
(根据上面 Oracle 的其他引用中看到的语言,默认的系统类加载器也称为“用户类”的类加载器。为同一件事想出 2 个名称的 Oracle。)
一个合适的答案是:
这也澄清了最初的问题。
当你这样做时,
java -Djava.system.class.loader=com.test.MyClassLoader xxx
-D 选项用于在作为 JVM 启动的一部分加载的 java.lang.System 实例的 Properties 对象中设置系统属性。该选项仅更改内存中的属性。在下一次调用 XXX 类或其他一些类时,将再次加载作为 System 类一部分的默认属性。在这里,您已将 java.system.class.loader 属性设置为值 com.test.MyClassLoader。换句话说,您想用新的系统类加载器覆盖默认系统类加载器(也称为引导类加载器),以便调用您的类 XXX。作为 JVM 启动的一部分加载的默认系统类加载器将查找内存中的 java.system.class.loader 属性以查找覆盖系统类加载器的名称 - 如果设置(在您的情况下,
如果你写在你的 XXX 类的 main 方法中
System.out.println(ClassLoader.getSystemClassLoader());
System.out.println(MyClassLoader.class.getClassLoader());
你应该看到
MyClassLoader
(加载 XXX 的新系统类加载器)
sun.misc.Launcher$AppClassLoader
(加载新系统类加载器的默认系统类加载器)