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
相关产品推荐
相关产品推荐

