You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tomcat Embed 9版本无法创建API容器,求解决方法

Tomcat 9.x嵌入版搭配CXFServlet无法启动(8.x正常)的解决办法

问题场景

使用tomcat-embed-core 9.0.65版本启动嵌入式Tomcat,搭配CXFServlet、Spring ContextLoaderListener及Spring Security过滤器,容器启动后无法访问http://127.0.0.1:4434/test;切换至Tomcat 8.x系列版本(如8.5.41、8.5.82)则一切正常,且无明显错误日志输出。

可能原因及修复步骤

1. 补充Tomcat 9嵌入版缺失的依赖

Tomcat 9嵌入版默认不包含EL表达式实现,而Spring和CXF的初始化过程依赖EL支持。需在build.gradle中添加以下依赖:

implementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '9.0.65'
// 添加EL实现依赖,Tomcat9默认不包含
implementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-el', version: '9.0.65'

2. 修正Servlet注册与上下文绑定逻辑

Tomcat 9对Servlet上下文的绑定逻辑更严格,建议直接通过Context对象注册Servlet,并设置loadOnStartup确保启动时加载:
修改原代码中的Servlet注册部分:

// 替换原tServer.addServlet的调用,改为通过Context注册并设置启动加载
CXFServlet cxfServlet = new CXFServlet();
Tomcat.addServlet(ctx, CXFServlet.class.getSimpleName(), cxfServlet).setLoadOnStartup(1);
ctx.addServletMappingDecoded("/test/*", CXFServlet.class.getSimpleName());

3. 验证Spring与CXF版本兼容性

确保使用的Spring版本为5.x及以上(支持Servlet 4.0,Tomcat9对应的Servlet版本),CXF版本为3.3.x及以上(兼容Tomcat9)。若使用旧版本,需升级对应依赖:
示例Spring&CXF依赖(build.gradle):

implementation group: 'org.springframework', name: 'spring-web', version: '5.3.24'
implementation group: 'org.springframework.security', name: 'spring-security-web', version: '5.7.5'
implementation group: 'org.apache.cxf', name: 'cxf-rt-frontend-jaxrs', version: '3.5.2'

4. 开启Tomcat调试日志排查隐藏问题

若以上步骤仍未解决,需开启Tomcat的调试日志,查看启动过程中的细节:
添加日志依赖:

implementation group: 'org.apache.tomcat.embed', name: 'tomcat-embed-logging-juli', version: '9.0.65'

在项目根目录添加logging.properties文件:

handlers = java.util.logging.ConsoleHandler
.level = INFO
org.apache.catalina.level = FINE
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

修改后的完整代码示例

import java.io.File;
import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;

public class EmbeddedTomcatLauncher {
    public static void main(String[] args) throws Exception {
        Tomcat tServer = new Tomcat();
        tServer.setHostname("127.0.0.1");
        tServer.setPort(4434);
        tServer.getHost().setAppBase(".");
        Context ctx = tServer.addContext("/", new File(".").getAbsolutePath());
        
        // 修正Servlet注册方式,设置启动时加载
        CXFServlet cxfServlet = new CXFServlet();
        Tomcat.addServlet(ctx, CXFServlet.class.getSimpleName(), cxfServlet).setLoadOnStartup(1);
        ctx.addServletMappingDecoded("/test/*", CXFServlet.class.getSimpleName());
        
        ctx.addApplicationListener(ContextLoaderListener.class.getName());
        ctx.addParameter("contextClass", AnnotationConfigWebApplicationContext.class.getName());
        ctx.addParameter("contextConfigLocation", RestConfig.class.getName());
        
        // 过滤器配置保持不变
        Class filterClass = DelegatingFilterProxy.class;
        FilterDef myFilterDef = new FilterDef();
        myFilterDef.setFilterClass(filterClass.getName());
        myFilterDef.setFilterName("springSecurityFilterChain");
        ctx.addFilterDef(myFilterDef);

        FilterMap myFilterMap = new FilterMap();
        myFilterMap.setFilterName("springSecurityFilterChain");
        myFilterMap.addURLPattern("/*");
        ctx.addFilterMap(myFilterMap);

        tServer.start();
        tServer.getServer().await();
    }
}

内容的提问来源于stack exchange,提问作者Bhoomika

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 12:05:17