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

发布于:2025-09-13 ⋅ 阅读:(15) ⋅ 点赞:(0)

Tomcat 通过 自定义类加载器 WebAppClassLoader 打破双亲委派机制,核心逻辑是 优先从 Web 应用本地目录加载类,而非直接委托父加载器。具体实现如下:

  1. 重写 loadClass 方法
    Tomcat 的 WebAppClassLoader 覆盖了 ClassLoaderloadClass 方法,默认流程为:
    • 先检查本地缓存(已加载的类)。
    • 尝试通过 ExtClassLoader 加载(防止 Web 应用覆盖 JVM 核心类,如 java.lang.Object)。
    • 在 Web 应用目录(WEB-INF/classes WEB-INF/lib)中查找类
    • 若本地未找到,再委托给父加载器(如 AppClassLoader)。
  1. 类加载顺序的调整
    默认双亲委派是“父优先”,而 Tomcat 的 WebAppClassLoader 通过以下调整实现“子优先”:

// 简化代码示例(实际逻辑更复杂)
public Class<?> loadClass(String name) {
// 1. 检查本地是否已加载
Class<?> clazz = findLoadedClass(name);
if (clazz == null) {
    // 2. 优先从 Web 应用目录加载
    clazz = findClass(name); 
    if (clazz == null) {
        // 3. 委托父加载器加载
        clazz = super.loadClass(name);
    }
}
return clazz;
}

这种设计使得 Web 应用可以覆盖容器或 JDK 的类(如日志框架),但核心类(如 java.lang.String)仍由父加载器加载

Tomcat 的类加载顺序分为 多层级加载策略,具体如下:

  1. 类加载器层级
    • Bootstrap ClassLoader:加载 JVM 核心类(JAVA_HOME/jre/lib)。
    • System ClassLoader:加载 Tomcat 启动类(如 catalina.jar)。
    • Common ClassLoader:加载 Tomcat 公共类($CATALINA_HOME/lib)。
    • Shared ClassLoader:加载所有 Web 应用共享的类。
    • WebAppClassLoader:每个 Web 应用独立的类加载器,加载 WEB-INF/classesWEB-INF/lib
  1. 具体加载流程
    当 Web 应用请求加载类时,顺序为:
    1. 检查本地缓存(WebAppClassLoader)。
    2. 委托 ExtClassLoader 加载(防止覆盖核心类)。
    3. WEB-INF/classes 中查找类。
    4. WEB-INF/lib 的 JAR 包中查找类。
    5. 委托 CommonSharedSystemBootstrap 加载