Launcher类部分内容分析
三种类加载器之间的关系
内建于JVM中的启动类加载器会加载java.lang.ClassLoder
以及其他Java平台类,当JVM启动时,一块特殊的机器码会运行,它会加载扩展类加载器与系统类加载器,这块特殊的机器码叫做启动类加载器(Bootstrap)。
启动类加载器不是Java类,而其他的加载器则都是Java类,启动类加载器是特定于平台的机器指令,它负责开启整个过程。
所有类加载器(除了启动类加载器)都被实现为Java类。不过,总归要有一个组件来加载第一个Java类加载器,从而让整个加载过程能够顺利进行下去,加载第一个纯Java类加载器就是启动类加载器的职责。
启动类加载器还会负责加载供JRE正常运行所需要的基本组件,这包括java.util
与java.lang
包中的类等等。
验证 1 2 System.out.println(ClassLoader.class.getClassLoader());
但是不能直接获取扩展类加载器和系统类加载器,因为没有声明这两个类为public
1 2 3 4 5 6 7 8 9 10 public class Launcher { ... static class AppClassLoader extends URLClassLoader { ... } static class ExtClassLoader extends URLClassLoader { ... } ... }
但是我们可以用Launcher类的类加载器验证
1 2 System.out.println(Launcher.class.getClassLoader());
所以扩展类加载器和系统类加载器也是由启动类加载器就加载的。
getSystemClassLoader 1 public static ClassLoader getSystemClassLoader ()
jdk8文档中有下面内容:
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
如果在首次调用此方法时定义了系统属性“java.system.class.loader”,那么该属性的值将被视为系统类加载器返回的类的名称。使用默认的系统类加载器加载该类,并且必须定义一个公共构造函数,该构造函数接受类型为ClassLoader的单个参数,该参数用作委托父类。然后使用此构造函数创建一个实例,并使用默认的系统类加载器作为参数。生成的类加载器被定义为系统类加载器。
那么就是说,如果我们想要更改系统类加载器为自定义类加载器,一是得改变java.system.class.loader
,二是在我们的自定义类加载器中添加一个参数为ClassLoader的构造函数
首先,未更改java.system.class.loade
时,输出其值:
1 2 3 System.out.println(System.getProperty("java.system.class.loader" ));
可以发现此时该属性值为null,如果我们不加上面所说的构造函数,直接更改属性值去加载别的类,那么会抛出异常
1 java -Djava.system.class.loader=indi.greenhat.jvm.CustomClassLoader indi.greenhat.jvm.Test
在CustomClassLoader中加入
1 2 3 public CustomClassLoader (ClassLoader parent) { super (parent); }
然后就会输出
1 indi.greenhat.jvm.CustomClassLoader
为什么要加入一个这样的方法呢?
这个与ClassLoader类里面的一个SystemClassLoaderAction类的run方法有关,此方法处理了用户自定义java.system.class.loader
属性的情况。处理方法如下:
1 2 3 4 5 Constructor<?> ctor = Class.forName(cls, true , parent) .getDeclaredConstructor(new Class<?>[] { ClassLoader.class }); ClassLoader sys = (ClassLoader) ctor.newInstance( new Object[] { parent });
因为这时候需要传递一个parent参数进去。
Launcher构造方法 来自openjdk8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public Launcher () { ClassLoader extcl; try { extcl = ExtClassLoader.getExtClassLoader(); } catch (IOException e) { throw new InternalError( "Could not create extension class loader" , e); } try { loader = AppClassLoader.getAppClassLoader(extcl); } catch (IOException e) { throw new InternalError( "Could not create application class loader" , e); } Thread.currentThread().setContextClassLoader(loader); String s = System.getProperty("java.security.manager" ); if (s != null ) { SecurityManager sm = null ; if ("" .equals(s) || "default" .equals(s)) { sm = new java.lang.SecurityManager(); } else { try { sm = (SecurityManager)loader.loadClass(s).newInstance(); } catch (IllegalAccessException e) { } catch (InstantiationException e) { } catch (ClassNotFoundException e) { } catch (ClassCastException e) { } } if (sm != null ) { System.setSecurityManager(sm); } else { throw new InternalError( "Could not create SecurityManager: " + s); } } }
ExtClassLoader 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 static class ExtClassLoader extends URLClassLoader { static { ClassLoader.registerAsParallelCapable(); } public static ExtClassLoader getExtClassLoader () throws IOException { final File[] dirs = getExtDirs(); try { return AccessController.doPrivileged( new PrivilegedExceptionAction<ExtClassLoader>() { public ExtClassLoader run () throws IOException { int len = dirs.length; for (int i = 0 ; i < len; i++) { MetaIndex.registerDirectory(dirs[i]); } return new ExtClassLoader(dirs); } }); } catch (java.security.PrivilegedActionException e) { throw (IOException) e.getException(); } }
ExtClassLoader继承树
可以看到ExtClassLoader
最终还是继承于ClassLoader
getExtDirs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private static File[] getExtDirs() { String s = System.getProperty("java.ext.dirs" ); File[] dirs; if (s != null ) { StringTokenizer st = new StringTokenizer(s, File.pathSeparator); int count = st.countTokens(); dirs = new File[count]; for (int i = 0 ; i < count; i++) { dirs[i] = new File(st.nextToken()); } } else { dirs = new File[0 ]; } return dirs; }
getAppClassLoader 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 static class AppClassLoader extends URLClassLoader { static { ClassLoader.registerAsParallelCapable(); } public static ClassLoader getAppClassLoader (final ClassLoader extcl) throws IOException { final String s = System.getProperty("java.class.path" ); final File[] path = (s == null ) ? new File[0 ] : getClassPath(s); return AccessController.doPrivileged( new PrivilegedAction<AppClassLoader>() { public AppClassLoader run () { URL[] urls = (s == null ) ? new URL[0 ] : pathToURLs(path); return new AppClassLoader(urls, extcl); } }); } AppClassLoader(URL[] urls, ClassLoader parent) { super (urls, parent, factory); }