ClassLoader

ClassLoader类结构

ClassLoader通常会用到:

  • defineClass(byte[],int,int)

  • findClass(String)

  • loadClass(String)

  • resolveClass(Class<?>)

defineClass()通常是和findClass()方法一起使用的,我们通过直接覆盖ClassLoader父类的findClass方法来实现类的加载规则,从而取得要加载类的字节码。然后调用defineClass方法生成类的Class对象, 如果想在类被加载到JVM时就被Link,那么可以调用resolveClass方法。

如果不想重新定义加载类的规则,也没有复杂的处理逻辑,只想在运行时能够加载自己的一个类,直接调用loadClass方法获取这个类的Class对象。

下面会以Tomcat的ClassLoader举例体会ClassLoader的设计、应用

JVM提供的ClassLoader

整个JVM平台提供三层ClassLoader:

  • BootstrapClassLoader根类加载器,它主要加载JVM自身工作需要的类,同时它是有JVM自己控制的,我们访问不到这个类

  • ExtClassLoader扩展类加载器,加载位置:jre\lib\ext,ExtClassLoder是顶层父类

  • AppClassLoader应用类加载器,父类是ExtClassLoader,如果自己实现类加载器,不管直接实现抽象类ClassLoader,还是继承URLClassLoader等,它的父加载器都是AppClassLoader。加载位置:classpath

类加载过程

  1. findClass 先找到.class文件并加载到内存中

  2. Linking

    • .class文件规范验证,对于类的字节码要做检测,保证格式正确、行为正确。

    • Class类数据结构分析以及内存分配,在这个阶段准备代表每个类总定义的字段、方法和实现接口所必需的数据结构

    • 解析,在这个阶段类装入器装入类所引用的其他所有类。

  3. init 类中静态属性和初始化赋值,以及静态块的执行

Tomcat的ClassLoader

Tomcat的非JVM顶级ClassLoader是StandardClassloader,它是在Bootstrap类的initClassLoader方法中创建的, Bootstrap调用ClassLoaderFactory的createClassLoader()方法创建StandardClassLoader对象。默认指定AppClassLoader为它的父类

我们知道,一个应用在tomcat中由一个StandardContext来表示,由StandardContext来解释Web应用的web.xml配置文件实例化所有的Servlet。 那么Servlet是如何被加载的呢?StandardContext类的startInternal()方法在StandardContext初始化时会检查loader是否存在,不存在就创建一个WebappLoader对象,

if(getLoader()=null){
    WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
    webappLoader.setDelegate(getDelegate()); setLoader(webappLoader);
}

再看StandardWrapper类的loadServlet()方法可以发现,所有的Servlet都是InstanceManager实例化的,而且这个类的ClassLoader也是获取StandardContext的Loader中的ClassLoader, 也就是前面设置的WebappClassLoader,所以Servlet的ClassLoader是Webapploader。

WebappClassLoader的加载机制如下: 1. 首先检查在WebappClassLoader中是否已经加载过了,是的话一定在缓存容器resourceEntries中 2. 否则,用findLoadedClass()方法继续检查在JVM中是否已经加载过 3. 如果都没有,先调用AppClassLoader加载请求的类,也就是在classpath中寻找 4. 检查请求的类是否在packageTriggers定义的包名下,如果在则通过StandardClassLoader类来加载它。 5. 如果依然没有找到,将由WebappClassLoader来加载,

自定义ClassLoader

import java.net.URL;
import java.net.URLClassLoader;

/**
 * @program: sortalgorithm
 * @description:
 * @author: John_Xia
 * @create: 2018-11-29 17:08
 */
public class URLPathClassLoader extends URLClassLoader {

    private String pakName="com.xsj.sortalgorithm";
    public URLPathClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    protected Class<?> findClass(String name) throws ClassNotFoundException{
        Class<?> aClass=findLoadedClass(name);
        if(aClass!=null){
            return aClass;
        }
        if(!pakName.startsWith(name)){
            return super.loadClass(name);
        }else {
            return findClass(name);
        }

    }
}

将指定目录转化成URL路径,然后作为参数创建URLPathClassLoader对象,那么这个ClassLoader在加载的时候就在URL指定的目录下查找指定的类文件。

Last updated