JVM的基础——ClassLoader分类
首先普及ClassLoader的基础:所有的Java类都是由ClassLoader由class文件加载进内存的,对于一个类,其唯一标识就是类名+加载他的ClassLoader(亦即对于不同的 ClassLoader,即使是加载了同一个Class也不能互通,本质上是两个类),其基本的分类如下图:
BootstrapClassLoader是一个特殊的ClassLoader,负责启动时加载jre的类库。并不继承于ClassLoader,因为是jvm逻辑的一部分;
ExtClassLoader也会加载jre类库,但是会加载那些额外的扩展类库(jre\lib\ext目录),到这个级别的
类加载器已经可以直接在代码中使用了; AppClassLoader是加载用户编写代码的
类加载器,会加载所有classpath路径下的类,所以这也是默认的系统 类加载器,默认通过调用ClassLoader.getSystemClassLoader()可以获取; 用户也可以自定义其它ClassLoader,继承于ClassLoader下的自定义
类加载器。
我们通过查看源码可以看到继承于ClassLoader的加载器(除去我们看不到的BootstrapClassLoader)在
ExtClassLoader
ExtClassLoader是
static class ExtClassLoader extendsURLClassLoader { private static volatile Launcher.ExtClassLoader instance; // Launcher通过这个方法获取ExtLoader实例,线程安全 public static Launcher.ExtClassLoader getExtClassLoader() throws IOException { if (instance == null) { Class var0 = Launcher.ExtClassLoader.class; synchronized( Launcher.ExtClassLoader.class) { if (instance == null) { instance = createExtClassLoader(); } } } return instance; } private static Launcher.ExtClassLoader createExtClassLoader() throws IOException { try { return ( Launcher.ExtClassLoader)AccessController .doPrivileged(new PrivilegedExceptionAction< Launcher.ExtClassLoader>() { public Launcher.ExtClassLoader run() throws IOException { File[] var1 = Launcher.ExtClassLoader.getExtDirs(); int var2 = var1.length; for(int var3 = 0; var3 < var2; ++var3) { MetaIndex.registerDirectory(var1[var3]); } return new Launcher.ExtClassLoader(var1); } }); } catch (PrivilegedActionException var1) { throw (IOException)var1.getException(); } } public ExtClassLoader(File[] var1) throws IOException { super(getExt URLs(var1), (ClassLoader)null, Launcher.factory); SharedSecrets.getJavaNetAccess().get URLClassPath(this).initLookupCache(this); } //获取ClassLoader的文件目录集合 //var0最后的值为 xxx\jre\lib\ext; 等 private static File[] getExtDirs() { String var0 = System.getProperty("java.ext.dirs"); File[] var1; if (var0 != null) { StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator); int var3 = var2.countTokens(); var1 = new File[var3]; for(int var4 = 0; var4 < var3; ++var4) { var1[var4] = new File(var2.nextToken()); } } else { var1 = new File[0]; } return var1; } //…………………… }
AppClassLoader
同ExtClassLoader也会内部静态类:
static class AppClassLoader extendsURLClassLoader { final URLClassPath ucp = SharedSecrets.getJavaNetAccess().get URLClassPath(this); public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException { final String var1 = System.getProperty("java.class.path"); final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1); return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction< Launcher.AppClassLoader>() { public Launcher.AppClassLoader run() { URL[] var1x = var1 == null ? new URL[0] : Launcher.pathTo URLs(var2); return new Launcher.AppClassLoader(var1x, var0); } }); } AppClassLoader( URL[] var1, ClassLoader var2) { //将var2作为parent super(var1, var2, Launcher.factory); this.ucp.initLookupCache(this); } public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException { int var3 = var1.lastIndexOf(46); if (var3 != -1) { SecurityManager var4 = System.getSecurityManager(); if (var4 != null) { var4.checkPackageAccess(var1.substring(0, var3)); } } if (this.ucp.knownToNotExist(var1)) { Class var5 = this.findLoadedClass(var1); if (var5 != null) { if (var2) { this.resolveClass(var5); } return var5; } else { throw new ClassNotFoundException(var1); } } else { return super.loadClass(var1, var2); } } }
双亲委派加载模型及其实现
在一个
创建ClassLoader:
publicLauncher() { Launcher.ExtClassLoader var1; try { //创建ExtClassLoader var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try { //创建了AppClassLoader,将ExtClassLoader作为参数传入 //上面的super(var1, var2, Launcher.factory); 一行 this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9); }
其中创建ClassLoader的super语句首行直接将传入的ClassLoader作为了parent:
private ClassLoader(Void unused, ClassLoader parent) { this.parent = parent; //………… }
在loadClass方法中:
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { //有父加载器先从父加载器中加载class if (parent != null) { c = parent.loadClass(name, false); //没有父加载器,则从bootStrap加载器中加载class } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { //都没有加载到,才从本加载器中进行class的加载 // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }