我们知道我们可以使用:
覆盖系统classloaderjava -Djava.system.class.loader=com.test.MyClassLoader xxx
然后,由于com.test.MyClassLoader
本身就是一个类,它是由谁加载的?
我们如何获取这个“meta”类加载器的类文件?
答案 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
环境变量
您可以尝试通过“java.system.class.loader”属性注入自定义类加载器(请参阅ClassLoader#getSystemClassLoader)。
Default System class loader
是MyClassLoader实例的父级,
答案 1 :(得分:19)
来自ClassLoader.getSystemClassLoader
的Javadoc:
如果在首次调用此方法时定义了系统属性“java.system.class.loader”,那么该属性的值将被视为将作为系统类加载器返回的类的名称。 使用默认的系统类加载器加载类,并且必须定义一个公共构造函数,该构造函数接受一个类型为ClassLoader的参数,该参数用作委托父级。
默认的系统类加载器本身特定于JVM实现。
答案 2 :(得分:8)
§ ..该属性的值被视为将作为系统类加载器返回的类的名称。使用默认系统类加载器 ..
加载该类
..因此,如果您的类加载器将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环境变量。
我们可以证明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
(加载新系统类加载器的默认系统类加载器)