【Tomcat8源码学习之四】Tomcat类加载器

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;
    }
}

参考:
图解Tomcat类加载机制

猜你喜欢

转载自www.cnblogs.com/cac2020/p/12759318.html