tomcat为什么要违背双亲委托机制

1. 什么是双亲委托机制

双亲委托的含义:

1) 加载的顺序固定:  引导类加载器--》扩展类加载器--》应用类加载器---》自定义类加载器 

2) 当我们使用扩展类加载器加载某个类的时候,若引导类加载器已经加载的该类,就不会继续加载过程

3) 下一级类加载器的加载过程依赖上一级类加载器

4)jdk核心class只能被加载一次

双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派父类加载器去完成。每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个请求时,子加载器才会尝试自己去加载。

2. tomcat的类加载机制

 

3. 双亲委托能否满足tomcat的业务需求

1) tomcat需要保证各个web项目的类独立加载,不同项目的相同jar可能版本不一致,需要保持依赖Jar相互独立

2)  web容器依赖的类库与web项目依赖的类库隔离

3)jsp热部署的实现

 默认的类加载机制需要保证class的唯一性,不能满足上述需求,也不能实现热部署。需要自定义类加载器。

 

4.tomcat 为什么要违背双亲委托机制

1) 双亲委托机制不能满足tomcat的业务需求

2) Webapp类加载器需要独立加载自身的class以及依赖的jar

3) 例如,webapp1依赖的spring版本为4.x,另一个依赖的spring版本为5.x. 如果使用双亲委托,那么spring的版本只能存在一个,没法满足这个需求

4) tomcat 自身依赖的jar可能和项目依赖的jar有重合的地方,比如servlet.jar,  此时优先webapp的jar加载

5. tomcat如何解决class隔离问题

每个Webapp类加载器独立去加载WEB-INF/lib与WEB-INF/classes目录下的class或ja

线程上下文加载器: 父类加载器请求子类加载器去完成类加载的动作,完成逆向双亲委托加载流程。

线程上下文类加载器(Thread Context ClassLoader):这个类加载器可以通过java.lang.Thread类的setContextClassLoader方法进行设置。如果创建线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认即使应用程序类加载器。

6. 源码实现

public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    synchronized(JreCompat.isGraalAvailable() ? this : this.getClassLoadingLock(name)) {
        if (log.isDebugEnabled()) {
            log.debug("loadClass(" + name + ", " + resolve + ")");
        }

        Class<?> clazz = null;
        this.checkStateForClassLoading(name);
        // 从本地缓存中查找
        clazz = this.findLoadedClass0(name);
        if (clazz != null) {
            if (log.isDebugEnabled()) {
                log.debug("  Returning class from cache");
            }

            if (resolve) {
                this.resolveClass(clazz);
            }

            return clazz;
        }
        // 从系统类加载器缓存中查找,已加载的类都会加入缓存
        clazz = JreCompat.isGraalAvailable() ? null : this.findLoadedClass(name);
        if (clazz != null) {
            if (log.isDebugEnabled()) {
                log.debug("  Returning class from cache");
            }

            if (resolve) {
                this.resolveClass(clazz);
            }

            return clazz;
        }

        String resourceName = this.binaryNameToPath(name, false);
        // 使用扩展类加载器加载,而没有使用系统类加载器,违背了双亲委托加载机制,目的是隔离
        ClassLoader javaseLoader = this.getJavaseClassLoader();

        boolean tryLoadingFromJavaseLoader;
        try {
            URL url;
            if (this.securityManager != null) {
                PrivilegedAction<URL> dp = new WebappClassLoaderBase.PrivilegedJavaseGetResource(resourceName);
                url = (URL)AccessController.doPrivileged(dp);
            } else {
                url = javaseLoader.getResource(resourceName);
            }

            tryLoadingFromJavaseLoader = url != null;
        } catch (Throwable var13) {
            ExceptionUtils.handleThrowable(var13);
            tryLoadingFromJavaseLoader = true;
        }

        Class var10000;
        if (tryLoadingFromJavaseLoader) {
            label218: {
                try {
                    clazz = javaseLoader.loadClass(name);
                    if (clazz == null) {
                        break label218;
                    }

                    if (resolve) {
                        this.resolveClass(clazz);
                    }

                    var10000 = clazz;
                } catch (ClassNotFoundException var15) {
                    break label218;
                }

                return var10000;
            }
        }

        if (this.securityManager != null) {
            int i = name.lastIndexOf(46);
            if (i >= 0) {
                try {
                    this.securityManager.checkPackageAccess(name.substring(0, i));
                } catch (SecurityException var12) {
                    String error = sm.getString("webappClassLoader.restrictedPackage", new Object[]{name});
                    log.info(error, var12);
                    throw new ClassNotFoundException(error, var12);
                }
            }
        }

        boolean delegateLoad = this.delegate || this.filter(name, true);
        if (delegateLoad) {
            label219: {
                if (log.isDebugEnabled()) {
                    log.debug("  Delegating to parent classloader1 " + this.parent);
                }

                try {
                    clazz = Class.forName(name, false, this.parent);
                    if (clazz == null) {
                        break label219;
                    }

                    if (log.isDebugEnabled()) {
                        log.debug("  Loading class from parent");
                    }

                    if (resolve) {
                        this.resolveClass(clazz);
                    }

                    var10000 = clazz;
                } catch (ClassNotFoundException var17) {
                    break label219;
                }

                return var10000;
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("  Searching local repositories");
        }

        label181: {
            try {
                clazz = this.findClass(name);
                if (clazz == null) {
                    break label181;
                }

                if (log.isDebugEnabled()) {
                    log.debug("  Loading class from local repository");
                }

                if (resolve) {
                    this.resolveClass(clazz);
                }

                var10000 = clazz;
            } catch (ClassNotFoundException var16) {
                break label181;
            }

            return var10000;
        }

        if (delegateLoad) {
            throw new ClassNotFoundException(name);
        }

        if (log.isDebugEnabled()) {
            log.debug("  Delegating to parent classloader at end: " + this.parent);
        }

        try {
            clazz = Class.forName(name, false, this.parent);
            if (clazz != null) {
                if (log.isDebugEnabled()) {
                    log.debug("  Loading class from parent");
                }

                if (resolve) {
                    this.resolveClass(clazz);
                }

                var10000 = clazz;
                return var10000;
            }
        } catch (ClassNotFoundException var14) {
            ;
        }
    }

    throw new ClassNotFoundException(name);
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值