当前位置: 首页 > news >正文

Tomcat打破双亲委派模型

tomcat的类加载器结构

tomcat的类加载(loadClass)过程

和原本的双亲委派模型思路差不多,先看有没有加载过。

  1. 先在本地 Cache 查找该类是否已经加载过,也就是说 Tomcat 的类加载器是否已经加载过这个类。

  1. 如果 Tomcat 类加载器没有加载过这个类,再看看系统类加载器是否加载过。

  1. 如果都没有,就让ExtClassLoader去加载,这一步比较关键,目的防止 Web 应用自己的类覆盖 JRE 的核心类。因为 Tomcat 需要打破双亲委托机制,假如 Web 应用里自定义了一个叫 Object 的类,如果先加载这个 Object 类,就会覆盖 JRE 里面的那个 Object 类,这就是为什么 Tomcat 的类加载器会优先尝试用 ExtClassLoader 去加载,因为 ExtClassLoader 会委托给 BootstrapClassLoader 去加载,BootstrapClassLoader 发现自己已经加载了 Object 类,直接返回给 Tomcat 的类加载器,这样 Tomcat 的类加载器就不会去加载 Web 应用下的 Object 类了,也就避免了覆盖 JRE 核心类的问题。

  1. 如果 ExtClassLoader 加载器加载失败,也就是说 JRE 核心类中没有这类,那么就在本地 Web 应用目录下查找并加载。

  1. 如果本地目录下没有这个类,说明不是 Web 应用自己定义的类,那么由系统类加载器去加载。这里请你注意,Web 应用是通过Class.forName调用交给系统类加载器的,因为Class.forName的默认加载器就是系统类加载器。

  1. 如果上述加载过程全部失败,抛出 ClassNotFound 异常。

public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
 
    synchronized (getClassLoadingLock(name)) {
 
        Class<?> clazz = null;
 
        //1. 先在本地 cache 查找该类是否已经加载过
        clazz = findLoadedClass0(name);
        if (clazz != null) {
            if (resolve)
                resolveClass(clazz);
            return clazz;
        }
 
        //2. 从系统类加载器的 cache 中查找是否加载过
        clazz = findLoadedClass(name);
        if (clazz != null) {
            if (resolve)
                resolveClass(clazz);
            return clazz;
        }
 
        // 3. 尝试用 ExtClassLoader 类加载器类加载,为什么?
        ClassLoader javaseLoader = getJavaseClassLoader();
        try {
            clazz = javaseLoader.loadClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return clazz;
            }
        } catch (ClassNotFoundException e) {
            // Ignore
        }
 
        // 4. 尝试在本地目录搜索 class 并加载
        try {
            clazz = findClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return clazz;
            }
        } catch (ClassNotFoundException e) {
            // Ignore
        }
 
        // 5. 尝试用系统类加载器 (也就是 AppClassLoader) 来加载
            try {
                clazz = Class.forName(name, false, parent);
                if (clazz != null) {
                    if (resolve)
                        resolveClass(clazz);
                    return clazz;
                }
            } catch (ClassNotFoundException e) {
                // Ignore
            }
       }
    
    //6. 上述过程都加载失败,抛出异常
    throw new ClassNotFoundException(name);
}

tomcat的类加载(findClass)过程

public Class<?> findClass(String name) throws ClassNotFoundException {
    ...
    
    Class<?> clazz = null;
    try {
            //1. 先在 Web 应用目录下查找类 
            clazz = findClassInternal(name);
    }  catch (RuntimeException e) {
           throw e;
       }
    
    if (clazz == null) {
    try {
            //2. 如果在本地目录没有找到,交给父加载器去查找
            clazz = super.findClass(name);
    }  catch (RuntimeException e) {
           throw e;
       }
    
    //3. 如果父类也没找到,抛出 ClassNotFoundException
    if (clazz == null) {
        throw new ClassNotFoundException(name);
     }
 
    return clazz;
}

findClass方法大致步骤:

  1. 先在 Web 应用本地目录下查找要加载的类。

  1. 如果没有找到,交给父加载器去查找,它的父加载器就是上面提到的系统类加载器 AppClassLoader。

  1. 如何父加载器也没找到这个类,抛出 ClassNotFound 异常。

Tomcat是如何打破双亲委派机制的呢?

Tomcat是先去本地目录加载,为了避免本地目录覆盖掉JRE的核心类,如java.lang包等,先尝试用ExtClassLoader加载,这样即能打破双亲委派机制,有避免了覆盖掉核心类。

为什么不是尝试用AppClassLoader加载呢?

如果是尝试用AppClassLoader,这样不又变会双亲委派机制了嘛。

相关文章:

  • 手机怎么建立自己的网站/市场营销推广方案模板
  • 便宜高端网站设计推荐/品牌营销策划有限公司
  • 网站开发人员配备/南昌做seo的公司有哪些
  • wordpress文章格式/网站推广方案策划
  • 佛山哪个做网站的好/树枝seo
  • 傻瓜式网站界面/宁波seo外包快速推广
  • A. Parallel Projection codeforces 1782A
  • echarts柱状图值为0是不显示以及柱状图百分比展示
  • [前端笔记——HTML介绍] 3.<head>标签里有什么?
  • ESP32设备驱动-TCS34725颜色传感器驱动
  • 系统分析师案例必备知识点汇总---2023系列文章二
  • Python学习笔记——控制流
  • AtCoder Beginner Contest 285解题报告
  • 【机器学习之模型融合】Blending混合法
  • 设计模式学习(七):Factory Method工厂模式
  • nn.Conv1d、nn.Conv2d、nn.Linear
  • 《Linux Shell脚本攻略》学习笔记-第九章
  • 【学习笔记】【Pytorch】、损失函数与反向传播