Tomcat类加载原理(WebappClassLoader)

关系图

这里写图片描述

源码分析


    //构造函数
    public WebappClassLoader(ClassLoader parent) {

        super(new URL[0], parent);
        //双亲委派
        this.parent = getParent();

        system = getSystemClassLoader();
        securityManager = System.getSecurityManager();

        if (securityManager != null) {
            refreshPolicy();
        }
    }

    //tomcat热部署的重点实现代码
    //loader不同,对相同的class文件的加载产生不同点类
    //热部署的时候通过loader的整体替换,达到热部署的目的
    //被loadClass调用
    public Class findClass(String name) throws ClassNotFoundException {

        //是否由父类来加载classes
        Class clazz = null;
        try {
            //优先自己加载
            if ((clazz == null)) {
                    clazz = findClassInternal(name);
            }
            //自己加载不成功时父类加载
            if ((clazz == null) && hasExternalRepositories && !searchExternalFirst) {
                    clazz = super.findClass(name);
            }
            //否则抛异常
            if (clazz == null) {
                throw new ClassNotFoundException(name);
            }
        } catch (ClassNotFoundException e) {
            throw e;
        }
        return (clazz);

    }

    public synchronized Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException {

        Class clazz = null;

        // (0) 检测自己的加载的缓存
        clazz = findLoadedClass0(name);
        if (clazz != null) {
            if (resolve)
                resolveClass(clazz);
            return (clazz);
        }

        // (0.1) 检测父类的加载的缓存
        clazz = findLoadedClass(name);
        if (clazz != null) {
            if (resolve)
                resolveClass(clazz);
            return (clazz);
        }

        // (0.2) 缓存中没有,则首先使用system类加载器来加载
        try {
            clazz = system.loadClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return (clazz);
            }
        } catch (ClassNotFoundException e) {
            // Ignore
        }

        // 判断是否需要先让parent代理
        boolean delegateLoad = delegate || filter(name);

        // (1) parent先加载 
        if (delegateLoad) {
            ClassLoader loader = parent;
            if (loader == null)
                loader = system;
            try {
                clazz = loader.loadClass(name);
                if (clazz != null) {
                    if (resolve)
                        resolveClass(clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                ;
            }
        }

        // (2) 以JDK推荐的方法加载类,自己重写的findClass方法,先自己加载,再父loader加载
        try {
            clazz = findClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return (clazz);
            }
        } catch (ClassNotFoundException e) {
            ;
        }

        // (3) 自己无法加载或者加载失败,请求parent加载
        if (!delegateLoad) {
            ClassLoader loader = parent;
            if (loader == null)
                loader = system;
            try {
                //递归至父loader加载
                clazz = loader.loadClass(name);
                if (clazz != null) {
                    if (resolve)
                        resolveClass(clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                ;
            }
        }

        throw new ClassNotFoundException(name);

    }

    //从ClassLoader继承过来的方法
    protected final Class<?> findLoadedClass(String name) {
        if (!checkName(name))
            return null;
        return findLoadedClass0(name);
    }

    private native final Class findLoadedClass0(String name);

    //WebappClassLoader类的方法
    protected Class findLoadedClass0(String name) {

        ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
        if (entry != null) {
            return entry.loadedClass;
        }
        return (null);  // FIXME - findLoadedResource()

    }

类缓存

tomcat之所以采用自定义类装载器,除了不同应用之间有相同类不好解决之外,还有一个原因是可以缓存类以提高速度。每个由webappclassloader装载的类被视为资源,用ResourceEntry表示。加入缓存的代码是在loadclass方法中完成的,前面提到会搜索本地仓库,就是在这步调用了findClass方法完成了类的查找,并把找到的类封装成ResourceEntry,最后把这个resourceEntry放入resourceEntries中缓存起来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值