Tomcat源码版本:apache-tomcat-8.5.54-src
JDK源码版本:jdk1.8.0_171
先来讲一下JVM的类加载机制。
一、JVM类加载机制
1、继承关系
ExtClassLoader和AppClassLoader都继承父类ClassLoader,ClassLoader有一个属性parent是实现双亲委派模型的关键属性。
2、双亲委派模型
2.1、Bootstrap ClassLoader:引导类加载器,是JVM内置native实现的。
(1)通过源码sun.misc.Launcher可以看得它的加载路径:
private static String bootClassPath = System.getProperty("sun.boot.class.path");
或者配置-Xbootclasspath参数指定加载的路径
具体加载了那些类:
%JAVA_HOME%\jre\lib\resources.jar %JAVA_HOME%\jre\lib\rt.jar %JAVA_HOME%\jre\lib\sunrsasign.jar %JAVA_HOME%\jre\lib\jsse.jar %JAVA_HOME%\jre\lib\jce.jar %JAVA_HOME%\jre\lib\charsets.jar %JAVA_HOME%\jre\lib\jfr.jar %JAVA_HOME%\jre\classes
(2)ClassLoader的findBootstrapClass方法指示Bootstrap ClassLoader是JVM内置实现的
private Class<?> findBootstrapClassOrNull(String name) { if (!checkName(name)) return null; return findBootstrapClass(name); } // return null if not found private native Class<?> findBootstrapClass(String name);
2.2、Extension ClassLoader:扩展类加载器,实现类为sun.misc.Launcher$ExtClassLoader,
(1)加载路径:String str = System.getProperty("java.ext.dirs");具体指:%JAVA_HOME%/jre/lib/ext
(2)创建扩展类加载器
源码:sun.misc.Launcher
ExtClassLoader localExtClassLoader; try { localExtClassLoader = ExtClassLoader.getExtClassLoader(); } catch (IOException localIOException1) { throw new InternalError("Could not create extension class loader", localIOException1); } //直接将parent属性设置为null 所以扩展类加载器的parent默认就是Bootstrap ClassLoader public ExtClassLoader(File[] var1) throws IOException { super(getExtURLs(var1), (ClassLoader)null, Launcher.factory); SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this); }
ClassLoader代码:
//ClassLoader有一个parent属性 private final ClassLoader parent; protected ClassLoader(ClassLoader parent) { this(checkCreateClassLoader(), parent); } private ClassLoader(Void unused, ClassLoader parent) { this.parent = parent; ...... } //加载类的方法主要是使用父类ClassLoader.loadClass方法: protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 首先,查找该类是否已经被加载过了 Class c = findLoadedClass(name); if (c == null) { //未被加载过 long t0 = System.nanoTime(); try { if (parent != null) { // 父类加载器不为null,则调用父类加载器尝试加载 c = parent.loadClass(name, false); } else { // 父类加载器为null,则调用本地方法,交由启动类加载器加载,所以说ExtClassLoader的父类加载器为Bootstrap ClassLoader c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { } if (c == null) { //仍然加载不到,只能由本加载器通过findClass去加载 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; } }
2.3、Appication ClassLoader:应用程序类加载器,或者叫系统类加载器,实现类为sun.misc.Launcher$AppClassLoader。
(1)加载路径:final String s = System.getProperty("java.class.path");
(2)具体实现
源码sun.misc.Launcher:
ExtClassLoader localExtClassLoader; try { localExtClassLoader = ExtClassLoader.getExtClassLoader(); } catch (IOException localIOException1) { throw new InternalError("Could not create extension class loader", localIOException1); } //直接将parent属性设置为null 所以扩展类加载器的parent默认就是Bootstrap ClassLoader public ExtClassLoader(File[] var1) throws IOException { super(getExtURLs(var1), (ClassLoader)null, Launcher.factory); SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this); } //应用类/系统类加载器 try { //将扩展类加载器作为参数传进去 实现双亲委托机制 loader = AppClassLoader.getAppClassLoader(localExtClassLoader); } catch (IOException localIOException2) { throw new InternalError("Could not create application class loader", localIOException2); } //当AppClassLoader被初始化以后,会被设置为当前线程的上下文类加载器以及保存到Launcher类的loader属性中, //而通过ClassLoader.getSystemClassLoader()获取的也正是该类加载器(Launcher.loader)。 Thread.currentThread().setContextClassLoader(loader); .... //var0为扩展类加载器 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.pathToURLs(var2); return new Launcher.AppClassLoader(var1x, var0); } }); } //var2为扩展类加载器 AppClassLoader(URL[] var1, ClassLoader var2) { super(var1, var2, Launcher.factory); this.ucp.initLookupCache(this); }
ClassLoader代码:
//ClassLoader有一个parent属性 private final ClassLoader parent; //最终调用父类ClassLoader构造方法 所以应用加载器的parent就是扩展类加载器 注意parent不是继承父类 protected ClassLoader(ClassLoader parent) { this(checkCreateClassLoader(), parent); } private ClassLoader(Void unused, ClassLoader parent) { this.parent = parent; ...... } //加载类的方法主要是使用父类ClassLoader.loadClass方法: protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 首先,查找该类是否已经被加载过了 Class c = findLoadedClass(name); if (c == null) { //未被加载过 long t0 = System.nanoTime(); try { if (parent != null) { // 父类加载器不为null,则调用父类加载器尝试加载 c = parent.loadClass(name, false); } else { // 父类加载器为null,则调用本地方法,交由启动类加载器加载,所以说ExtClassLoader的父类加载器为Bootstrap ClassLoader c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { } if (c == null) { //仍然加载不到,只能由本加载器通过findClass去加载 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; } }