Tomcat -- 类加载机制

JVM类加载机制

待补充

Tomcat类加载器

在这里插入图片描述

  • 引导类和扩展类加载器作用不变
  • 系统类加载器正常情况下加载的是classpath下的类,但是tomcat启动脚本并未使用该变量,而是加载tomcat启动类,如bootstrap.jar , 通常在catalina.bat或者catalina.sh中指定,位于catalina_home/bin下
  • common通用类加载器加载tomcat使用以及应用通用的一些类,位于catalina_home/lib下,如servlet-api.jar
  • catalinaClassloader用于加载服务器内部可见类,这些类应用程序访问不到
  • sharedClassLoader用于加载应用程序共享类,这些服务器不会依赖
  • webappClassloader每个应用程序都会有唯一的webappClassloader,用来加载本应用程序/WEB-INF/classes和/WEB-INF/lib下的类 , 不同的webappClassLoader相互隔离

tomcat打破双亲委派

  • 从缓存中加载
  • 如果没有,先调用ExtClassLoader,扩展类加载器会遵循双亲委派,会调用bootStrapClassloader
    a. 获取ExtClassLoader,尝试加载这个类,防止改写java底层类,如java.lang.Object 等
    b. 跳过AppClassLoader,达到打破双亲委派的效果,同时也避免底层类加载不到问题
  • 如果没有,则从当前类加载器加载,按照WEB-INF/classes , WEB-INF/lib 的顺序加载
  • 如果没有,从父类加载器加载,父类加载器默认委派,加载顺序为: Bootstarp/ExtClassLoader/System/common/Shard

源码 : org.apache.catalina.loader.WebappClassLoaderBase#loadClass(java.lang.String, boolean)

public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (JreCompat.isGraalAvailable() ? this : getClassLoadingLock(name)) {
            if (log.isDebugEnabled())
                log.debug("loadClass(" + name + ", " + resolve + ")");
            Class<?> clazz = null;
            // Log access to stopped class loader
            checkStateForClassLoading(name);
            // (0) Check our previously loaded local class cache
            //1,检查这个类是不是已经被加载缓存过(tomcat自定义Map缓存)
            clazz = findLoadedClass0(name);
            if (clazz != null) {
                if (log.isDebugEnabled())
                    log.debug("  Returning class from cache");
                if (resolve)
                    resolveClass(clazz);
                return clazz;
            }

            // (0.1) Check our previously loaded class cache
            //如果没被tomcat加载过,从jvm本地缓存中查找
            clazz = JreCompat.isGraalAvailable() ? null : findLoadedClass(name);
            if (clazz != null) {
                if (log.isDebugEnabled())
                    log.debug("  Returning class from cache");
                if (resolve)
                    resolveClass(clazz);
                return clazz;
            }

            // (0.2) Try loading the class with the system class loader, to prevent
            //       the webapp from overriding Java SE classes. This implements
            //       SRV.10.7.2
            String resourceName = binaryNameToPath(name, false);
            //获取ExtClassLoader,尝试加载这个类,防止改写java底层类,如java.lang.Object 等
            //跳过AppClassLoader,达到打破双亲委派的效果,同时也避免底层类加载不到问题
            ClassLoader javaseLoader = getJavaseClassLoader();
            boolean tryLoadingFromJavaseLoader;
            try {
                // Use getResource as it won't trigger an expensive
                // ClassNotFoundException if the resource is not available from
                // the Java SE class loader. However (see
                // https://bz.apache.org/bugzilla/show_bug.cgi?id=58125 for
                // details) when running under a security manager in rare cases
                // this call may trigger a ClassCircularityError.
                // See https://bz.apache.org/bugzilla/show_bug.cgi?id=61424 for
                // details of how this may trigger a StackOverflowError
                // Given these reported errors, catch Throwable to ensure any
                // other edge cases are also caught
                URL url;
                //安全管理器
                if (securityManager != null) {
                    PrivilegedAction<URL> dp = new PrivilegedJavaseGetResource(resourceName);
                    url = AccessController.doPrivileged(dp);
                } else {
                    url = javaseLoader.getResource(resourceName);
                }
                tryLoadingFromJavaseLoader = (url != null);
            } catch (Throwable t) {
                // Swallow all exceptions apart from those that must be re-thrown
                ExceptionUtils.handleThrowable(t);
                // The getResource() trick won't work for this class. We have to
                // try loading it directly and accept that we might get a
                // ClassNotFoundException.
                tryLoadingFromJavaseLoader = true;
            }

            if (tryLoadingFromJavaseLoader) {
                try {
                    clazz = javaseLoader.loadClass(name);
                    if (clazz != null) {
                        if (resolve)
                            resolveClass(clazz);
                        return clazz;
                    }
                } catch (ClassNotFoundException e) {
                    // Ignore
                }
            }

            // (0.5) Permission to access this class when using a SecurityManager
            if (securityManager != null) {
                int i = name.lastIndexOf('.');
                if (i >= 0) {
                    try {
                        securityManager.checkPackageAccess(name.substring(0, i));
                    } catch (SecurityException se) {
                        String error = sm.getString("webappClassLoader.restrictedPackage", name);
                        log.info(error, se);
                        throw new ClassNotFoundException(error, se);
                    }
                }
            }

            //是否配置了委派
            boolean delegateLoad = delegate || filter(name, true);
            // (1) Delegate to our parent if requested
            //委派给父类加载器先加载,比如tomcat中CommonClassLoader等,加载tomcat源码相关包路径的class
            if (delegateLoad) {
                if (log.isDebugEnabled())
                    log.debug("  Delegating to parent classloader1 " + parent);
                try {
                    //使用当前加载器的父类加载器去加载这个类(双亲委派)
                    clazz = Class.forName(name, false, parent);
                    if (clazz != null) {
                        if (log.isDebugEnabled())
                            log.debug("  Loading class from parent");
                        if (resolve)
                            resolveClass(clazz);
                        return clazz;
                    }
                } catch (ClassNotFoundException e) {
                    // Ignore
                }
            }

            // (2) Search local repositories
            if (log.isDebugEnabled())
                log.debug("  Searching local repositories");
            try {

                //如果没有加载到,再用自己的加载器加载
                clazz = findClass(name);
                if (clazz != null) {
                    if (log.isDebugEnabled())
                        log.debug("  Loading class from local repository");
                    if (resolve)
                        resolveClass(clazz);
                    return clazz;
                }
            } catch (ClassNotFoundException e) {
                // Ignore
            }

            // (3) Delegate to parent unconditionally
            //没有开启委派,自己classLoader加载不到
            if (!delegateLoad) {
                if (log.isDebugEnabled())
                    log.debug("  Delegating to parent classloader at end: " + parent);
                try {
                    //再由父类classLoader加载(双亲委派)
                    clazz = Class.forName(name, false, parent);
                    if (clazz != null) {
                        if (log.isDebugEnabled())
                            log.debug("  Loading class from parent");
                        if (resolve)
                            resolveClass(clazz);
                        return clazz;
                    }
                } catch (ClassNotFoundException e) {
                    // Ignore
                }
            }
        }

        throw new ClassNotFoundException(name);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值