较高版本Tomcat启动Spring-Mvc老项目报错

157 阅读2分钟

Tomcat 7.0.100 启动问题解决方案:web-fragment 冲突处理

问题简述

在升级 Tomcat 从 7.0.64 到 7.0.100 后,项目无法启动,出现以下错误:

四月 24, 2025 8:59:25 下午 org.apache.catalina.core.ContainerBase addChildInternal
严重: ContainerBase.addChild: start: 
org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]]
      at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:440)
      at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)

四月 24, 2025 8:59:25 下午 org.apache.tomcat.util.modeler.BaseModelMBean invoke
严重: Exception invoking method manageApp
java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]]
      at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)

四月 24, 2025 8:59:25 下午 org.apache.tomcat.util.modeler.BaseModelMBean invoke
严重: Exception invoking method createStandardContext
javax.management.RuntimeOperationsException: Exception invoking method manageApp
      at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:311)

解决方案

在 web.xml 中添加以下配置:

<absolute-ordering>
    <name>spring_web</name>
</absolute-ordering>

原理解析

1. absolute-ordering 的作用

  • 在 Servlet 3.0 规范中,引入了 web 片段(web fragments)的概念
  • 每个 jar 包可以包含一个 META-INF/web-fragment.xml 文件
  • 这些片段会被自动合并到主 web.xml 中
  •  用于明确指定这些片段的加载顺序

2. 问题原因

  • 项目中有多个依赖都包含了 spring_web 片段
  • 这些片段可能来自:

    • Spring Framework 的 spring-web 模块
    • Spring Security 的 web 模块
    • 其他 Spring 相关模块
  • 当有多个同名片段时,Tomcat 不知道应该使用哪一个

3. 版本差异

  • Tomcat 7.0.100(也不新) 对 Servlet 规范的实现更加严格
  • 老版本 可能对这种情况采取了更宽松的处理方式
  • 7.0.100 版本可能包含了一些安全补丁,要求更明确的配置

4. 工作原理

<absolute-ordering>
    <name>spring_web</name>
</absolute-ordering>
  • 这告诉 Tomcat 使用指定的 spring_web 片段
  • 忽略其他同名的片段
  • 确保只有一个 spring_web 片段被加载

关于 spring_web 片段

1. 来源

  • 主要来自 Spring Framework 的 spring-web 模块
  • 在 pom.xml 中对应的依赖:
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.version}</version>
    </dependency>

2. 内容

  • Spring MVC 的基础组件
  • Web 相关的工具类
  • HTTP 请求处理相关的类

3. 多个片段的来源

  • 可能来自不同的 Spring 模块:

    • spring-web
    • spring-webmvc
    • spring-security-web
    • 其他 Spring 相关模块
  • 每个模块可能都包含自己的 web-fragment.xml

命名约定说明

1. 为什么是 spring_web 而不是 spring-web

  • spring-web 是 Maven 依赖的 artifactId(项目标识符)
  • spring_web 是 web-fragment.xml 中定义的片段名称

2. 命名规则的区别

  • Maven:使用连字符(-)作为分隔符
  • XML:使用下划线()作为分隔符

最佳实践

  1. 在大型项目中,建议始终使用 absolute-ordering
  1. 明确列出所有需要的 web 片段
  1. 保持依赖版本的统一
  1. 了解底层机制,以便快速定位问题