30

我们知道我们可以覆盖 System类加载器

java -Djava.system.class.loader=com.test.MyClassLoader xxx

那么,既然com.test.MyClassLoader它本身就是一个类,那么它是由谁来加载的呢?

我们如何获得这个“元”类加载器的类文件?

4

4 回答 4

26

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 实例的父级,

于 2012-07-09T13:38:21.117 回答
21

来自 Javadoc 的ClassLoader.getSystemClassLoader

如果在首次调用此方法时定义了系统属性“java.system.class.loader”,则该属性的值将被视为将作为系统类加载器返回的类的名称。该类使用默认的系统类加载器加载,并且必须定义一个公共构造函数,该构造函数采用一个 ClassLoader 类型的参数,该参数用作委托父级。

默认系统类加载器本身特定于 JVM 实现。

于 2012-07-09T12:38:50.403 回答
9

语言:

§ ..该属性的值被视为将作为系统类加载器返回的类的名称。该类是使用默认的系统类加载器加载的..

..因此,如果您的类加载器将 X 替换为系统类加载器,那么您的类加载器的父级将是 X,即默认的系统类加载器。

(X 的类型类似于sun.misc.Launcher$AppClassLoader。)

更多信息可在docs.oracle.com - Java Launcher 如何查找类

Java 启动器 java 启动 Java 虚拟机。虚拟机按以下顺序搜索和加载类:

引导类- 组成 Java 平台的类,包括 rt.jar 中的类和其他几个重要的 jar 文件。

扩展类- 使用 Java 扩展机制的类。这些被捆绑为位于扩展目录中的 .jar 文件。

用户类- 由开发人员和第三方定义的不利用扩展机制的类。您可以使用命令行上的 -classpath 选项或使用 CLASSPATH 环境变量来识别这些类的位置。

tsmr:

我们可以证明 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。)

于 2014-08-24T23:59:43.377 回答
0

一个合适的答案是:

这也澄清了最初的问题。

当你这样做时,

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     

(加载新系统类加载器的默认系统类加载器)

于 2019-08-04T14:09:46.123 回答