什么加载java系统类加载器?

时间:2012-07-09 12:32:08

标签: java classloader

我们知道我们可以使用:

覆盖系统classloader
java -Djava.system.class.loader=com.test.MyClassLoader xxx

然后,由于com.test.MyClassLoader本身就是一个类,它是由谁加载的?

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

4 个答案:

答案 0 :(得分:23)

Bootstrap classloader是所有classloaders的父级,并在JRE(rt.jar和i18n.jar)的lib目录中加载标准JDK类。所有java。*类都由此classloader加载。

Extensions Classloader是Bootstrap类加载器的直接子代。该类加载器加载JRE的lib \ ext目录中的类。

System-Classpath classloader是Extensions类加载器的直接子项。它加载由CLASSPATH环境变量

指定的类和jar

您可以尝试通过“java.system.class.loader”属性注入自定义类加载器(请参阅ClassLoader#getSystemClassLoader)。

Default System class loader是MyClassLoader实例的父级,

答案 1 :(得分:19)

来自ClassLoader.getSystemClassLoader的Javadoc:

  

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

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

答案 2 :(得分:8)

Tldr:

  

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

加载该类

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

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

可在docs.oracle.com - How the Java Launcher Finds Classes找到更多信息:

  

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   
..及其类型:class sun.misc.Launcher $ AppClassLoader   
(MyCL的类加载器)的类加载器:null

我们可以看到MyCL的类加载器是sun.misc.Launcher$AppClassLoader,它是默认的系统类加载器。

(根据Oracle上面的其他引用中所见的语言,默认的系统类加载器也称为“用户类”的类加载器。为Oracle提供相同的2个名称。 )

答案 3 :(得分:0)

适当的答案是:

这也澄清了原始问题。

这样做的时候,

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

-D选项用于在java.lang.System实例的Properties对象中设置系统属性,该实例是作为JVM启动的一部分加载的。该选项仅更改内存中的属性。在下一次调用类XXX或其他类时,将再次加载作为System类一部分的默认属性。在这里,您已将java.system.class.loader属性设置为值com.test.MyClassLoader。换句话说,您要使用新的系统类加载器覆盖默认的系统类加载器(也称为引导类加载器),以调用类XXX。默认的系统类加载器是在JVM启动时加载的,它会在内存中查找java.system.class.loader属性,以查找您的重写系统类加载器的名称-如果已设置(在您的情况下,设置为MyClassLoader)-并从您的类路径中加载它,默认情况下是您的工作目录的根目录(应包含XXX),或者是classpath变量中的根目录(如果已定义,则为-cp或环境变量CLASSPATH)。

如果您在XXX类的main方法中写内容

    System.out.println(ClassLoader.getSystemClassLoader());
    System.out.println(MyClassLoader.class.getClassLoader());

您应该看到

  MyClassLoader      

(加载XXX的新系统类加载器)

 sun.misc.Launcher$AppClassLoader     

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