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

Docker容器中Tomcat运行时Servlet加载两次问题求助

问题分析

从你提供的堆栈跟踪能明显看到两次Servlet加载的触发路径差异:

  • 启动阶段:由StandardContext.loadOnStartup触发,这完全符合你在web.xml里配置load-on-startup:1的预加载预期
  • 首次请求阶段:由StandardWrapper.allocate触发,这说明Tomcat此时需要重新创建Servlet实例——意味着之前的实例已经被销毁,或者整个Web上下文被重新加载了

本地Tomcat正常但Docker环境异常,大概率是Docker镜像中的Tomcat默认配置和本地存在差异,导致了上下文重复部署/自动重新加载的问题。

可能的原因及解决方案

1. Tomcat自动部署特性触发重复部署

Docker官方的tomcat:8.5镜像默认同时开启了autoDeploy和deployOnStartup。容器启动时,Tomcat会先通过deployOnStartup部署ROOT.war,之后autoDeploy扫描目录时,可能会误判文件状态再次触发部署(即使WAR包本身没有变化)。

解决方法:
修改Tomcat的conf/server.xml中<Host>元素的配置,关闭自动部署:

<Host name="localhost"  appBase="webapps"
      unpackWARs="true" autoDeploy="false" deployOnStartup="true">

你可以在本地提前修改好server.xml,然后通过Dockerfile替换镜像中的默认配置:

FROM tomcat:8.5
RUN rm -rf /usr/local/tomcat/webapps/*
# 复制自定义的server.xml到镜像中
COPY conf/server.xml /usr/local/tomcat/conf/server.xml
ADD target/my-webapp.war /usr/local/tomcat/webapps/ROOT.war
ENV JPDA_ADDRESS="8000"
ENV JPDA_TRANSPORT="dt_socket"
ENV CATALINA_OPTS="-Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.port=8086 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false"
CMD ["catalina.sh", "jpda", "run"]

2. Context的reloadable属性导致自动重新加载

如果你的应用上下文配置了reloadable="true",Tomcat会持续监控WEB-INF目录下的文件变化,一旦检测到疑似变化就会重新加载上下文,进而导致Servlet被再次初始化。

解决方法:
检查conf/context.xml或者应用自身的META-INF/context.xml,确保reloadable设置为false:

<Context reloadable="false">

同样可以通过Dockerfile将修改后的配置文件复制到镜像中。

3. 验证方法

启动容器后,查看Tomcat的catalina.out日志,如果能看到类似Context [] started和Context [] reloaded的日志,就可以100%确认是上下文重新加载导致的Servlet重复初始化问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:25:30