继续前面两篇类加载器的内容,本篇补充总结类加载的一些关键问题。
- Java的类加载器本身如何被加载?
Java的根类加载器(Bootstrap Class Loader),由C++编写,它是内建在JVM方法区内的一块字节码,它java.lang.ClassLoader和java平台类。JVM启动时,根类加载器会加载扩展类加载器和系统类加载器。除了根类加载器,其他类加载器都是Java类。
1public class TestPath2 {
2 public static void main(String[] args) {
3 System.out.println("Laucher class loader:" + Launcher.class.getClassLoader());
4 }
5}
1Laucher class loader:null
2
3Process finished with exit code 0
Launcher类的类加载器是null,即为根类加载器,而AppClassLoader和ExtClassLoader是Launcher的内部类,也应由根类加载器加载。
2.自定义默认的系统类加载器
If the system property “java.system.class.loader” is defined when this method is first invoked then the value of that property is taken to be the name of a class that will be returned as the system class loader. The class is loaded using the default system class loader and must define a public constructor that takes a single parameter of type ClassLoader which is used as the delegation parent. An instance is then created using this constructor with the default system class loader as the parameter. The resulting class loader is defined to be the system class loader.
通过查看ClassLoader.getSystemClassLoader()的注释说明可知,在启动参数中设置-Djava.system.class.loader=自定义系统类加载器,这个自定义的类加载器要有一个参数为ClassLoader Parent 的构造方法,以便将AppClassLoader作为其父类加载器。
下面简单看下源码。
1public static ClassLoader getSystemClassLoader() {
2 initSystemClassLoader();//初始化
3 if (scl == null) {
4 return null;
5 }
6 SecurityManager sm = System.getSecurityManager();
7 if (sm != null) {
8 checkClassLoaderPermission(scl, Reflection.getCallerClass());
9 }
10 return scl;
11 }
ClassLoader类中定义了一个成员变量scl,指的是系统类加载器。 getSystemClassLoader()方法中调用initSystemClassLoader()方法来初始化系统类加载器,初始化之后做一些安全检查,然后直接返回。
1 private static synchronized void initSystemClassLoader() {
2 if (!sclSet) {
3 if (scl != null)
4 throw new IllegalStateException("recursive invocation");
5 sun.misc.Launcher l = sun.misc.Launcher.getLauncher();//获取Launcher
6 if (l != null) {
7 Throwable oops = null;
8 scl = l.getClassLoader();//返回AppClassLoader实例
9 try {
10 scl = AccessController.doPrivileged(
11 new SystemClassLoaderAction(scl));// 返回自定义处理过的系统类加载器
12 } catch (PrivilegedActionException pae) {
13 oops = pae.getCause();
14 if (oops instanceof InvocationTargetException) {
15 oops = oops.getCause();
16 }
17 }
18 if (oops != null) {
19 if (oops instanceof Error) {
20 throw (Error) oops;
21 } else {
22 // wrap the exception
23 throw new Error(oops);
24 }
25 }
26 }
27 sclSet = true;
28 }
29 }
在initSystemClassLoader()方法中,获取sun.misc.Launcher对象,由Launcher对象的getClassLoader直接返回AppClassLoader对象引用。创建Launcher对象的过程中会创建好AppClassLoader。第53行和第54行非常重要,它在构造方法中传入了AppClassLoader,作为父类加载器,给了用户一个自定义系统类加载器的机会。
1class SystemClassLoaderAction
2 implements PrivilegedExceptionAction<ClassLoader> {
3 private ClassLoader parent;
4
5 SystemClassLoaderAction(ClassLoader parent) {
6 this.parent = parent;
7 }
8
9 public ClassLoader run() throws Exception {
10 String cls = System.getProperty("java.system.class.loader");
11 if (cls == null) {//通常情况下这里为空,直接返回
12 return parent;
13 }
14
15 Constructor<?> ctor = Class.forName(cls, true, parent)
16 .getDeclaredConstructor(new Class<?>[] { ClassLoader.class });
17 ClassLoader sys = (ClassLoader) ctor.newInstance(
18 new Object[] { parent });
19 // 将新生成的类加载器设置到上下文类加载器中
20 Thread.currentThread().setContextClassLoader(sys);
21 return sys;
22 }
23}
SystemClassLoaderAction这个类比较简单,接收AppClassLoader作为parent,系统参数"java.system.class.loader"如果没有设置值,则直接返回。通常情况下,这个参数值为空,所以直接返回parent,也就是返回AppClassLoader作为系统类加载器。
如果设置了"java.system.class.loader"参数值,即自定义的类加载器,那么将通过反射实例化该类加载器,然后设置到上下文类加载器中,返回该自定义的类加载器作为系统类加载器。