外置tomcat启动后访问无响应排查

本文讲述了作者在外置Tomcat部署SpringBoot应用时遇到的死循环问题,涉及到项目启动时的远程调用冲突,最终通过源码分析和配置调整解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

自从使用springboot后,好久没有下载tomcat了,今天遇到一甲方爸爸要求使用外置tomcat,忽感菊花一紧,遇到安全意识较强的甲方了(此处由于笔者曾经供职过甲方,为什么需要用外置tomcat此处啰嗦一句:外置tomcat才能更好的控制安全-安全基线版本,不然springboot内部内置的tomcat甲方的技术管理部如何控制tomcat基线版本?),没办法,老老实实把客户分支代码打包方式修改为war吧。

二、出现问题

老老实实修改打包方式,增加SpringBootServletInitializer子类,然后就满怀期待打包,打包生成war一切都很顺利,对应ServletInitializer子类如下:

/**
 * 〈Servlet初始化〉<br> 
 * 〈外置tomcat启动引导〉
 *
 * @author ghostp
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
@Configuration
public class ServletInitializer extends SpringBootServletInitializer implements WebApplicationInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        setRegisterErrorPageFilter(false);
        builder.sources(DroolsApplication.class);
        return super.configure(builder);
    }
}

放到外置tomcat中,开始启动也是一切OK,并没有出现网上说的需要排内置tomcat问题。

可是启动后等待半天(此处项目工程启动需要加载较多信息入缓存和内存,故耗时较高),看一切都还OK,项目中启动加载数据和定时任务运行也是杠杠的(查看项目日志),自认为一切OK,访问 http://localhost:8081后发现长期等待,页面没有任何反应,查看页面tab一直在转圈,打开页面开发者工具,看到一直在等待

 这么看来是项目根本就没有启动完成?还是就是慢?尝试等待页面响应,再次等了10分钟,惊喜的发现没有出现访问超时错误,竟然还在等待。。。。这TM让人奔溃了。

没办法,继续分析吧。

三、分析之路

按照现象分析,肯定是项目没有启动完成,tomcat一直在等待,那么尝试使用tomcat控制台模式发布war是否可行呢?立马进行测试,此处需要注意,tomcat默认是没有用户的,需要大家配置,可以参见:Tomcat9配置进入manager webapp和HostManager页面_zjxht62的博客-优快云博客_tomcat9 webapp

 然后兴冲冲的进入manager管理进行war上传,

可惜,上传出错,

通过查看tomcat日志,发现是war包过大导致。

21-Jul-2022 17:42:54.392 严重 [http-nio-8081-exec-10] org.apache.catalina.core.ApplicationContext.log HTMLManager: 失败 - 部署上传失败,异常信息:[org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException: the request was rejected because its size (284113069) exceeds the configured maximum (52428800)]
	java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException: the request was rejected because its size (284113069) exceeds the configured maximum (52428800)
		at org.apache.catalina.connector.Request.parseParts(Request.java:2974)
		at org.apache.catalina.connector.Request.parseParameters(Request.java:3263)
		at org.apache.catalina.connector.Request.getParameter(Request.java:1141)
		at org.apache.catalina.connector.RequestFacade.getParameter(RequestFacade.java:381)
		at org.apache.catalina.filters.CsrfPreventionFilter.doFilter(CsrfPreventionFilter.java:127)
		at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
		at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
		at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
		at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
		at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
		at org.apache.catalina.filters.HttpHeaderSecurityFilter.doFilter(HttpHeaderSecurityFilter.java:126)
		at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
		at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
		at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
		at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
		at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:660)
		at org.apache.catalina.valves.RequestFilterValve.process(RequestFilterValve.java:378)
		at org.apache.catalina.valves.RemoteAddrValve.invoke(RemoteAddrValve.java:56)
		at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
		at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
		at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:687)
		at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
		at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)
		at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
		at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
		at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890)
		at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
		at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
		at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
		at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
		at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
		at java.lang.Thread.run(Thread.java:748)
	Caused by: org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException: the request was rejected because its size (284113069) exceeds the configured maximum (52428800)
		at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.init(FileItemIteratorImpl.java:161)
		at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.getMultiPartStream(FileItemIteratorImpl.java:205)
		at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.findNextItem(FileItemIteratorImpl.java:224)
		at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.<init>(FileItemIteratorImpl.java:142)
		at org.apache.tomcat.util.http.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:252)
		at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:276)
		at org.apache.catalina.connector.Request.parseParts(Request.java:2932)
		... 31 more

这时候N年前使用tomcat经验派上用途了,直接把war包提交到tomcat的webapps文件夹下面,然后不断刷新manager页面,终于看到自己上传的项目目录,

然后点击启动,(出去抽根烟,平静下心情)等待一段时间后发现是OK的,启动成功,这个... ...脑裂了,难道跟甲方爸爸说用控制台模式启动?服务器重启怎么办?这必须要解决啊,实施不吐槽,自己也过意不去。

四、项目源码分析

利索的,赶紧看看源码吧。

1、springboot的application.yml里面的端口跟tomcat端口一致,嗯....这里难道有冲突?不应该啊,修改后测试下,把application.yml的server.port端口修改为8080,再次启动,OK,启动成功了,此处再次去抽一支。

2、抽完回来后测试说项目很多功能包系统异常.......F**K,赶紧看看什么异常吧,看到日志中很多restTemplate远程调用不通,调用的端口号是8080。这下感觉醍醐灌顶了,原来项目为了微服务化处理,内部采用了远程调用非耦合工程,而本次给甲方爸爸的版本是代码库在一起的,统一打包的模式,配置服务化的配置中使用了${server.port}来获取了统一工程远程服务的地址。那就说明,项目启动过程中调用了远程服务?原来server.port的端口和tomcat端口不一致,restTemplate会自动失败,而如果端口一致,会出现死循环。

按照这个思路进行了排查(24个服务配置,按照二分法查找方式进行测试配置),终于在4次测试后发现了某个服务在项目启动过程中调用了,此处出现了死循环,启动中调用了远程服务获取数据,此处形成了死循环。

 tomcat等待项目启动结果,项目main线程远程调用了tomcat服务。。。。

而如果使用tomcat控制台发布,此处的tomcat主线程启动是成功状态,项目内部调用是OK的情况,故不出现死循环。

通过日志找到启动过程中远程调用的地方,发现确实有远程调用,先注释掉。

然后再进行启动,OK,tomcat启动成功,项目功能验证OK。

五、总结

问题处理完成了,此处问题出现也很奇葩,项目后期开发过程中需要进行代码审核,不能再出现此种现象。

tomcat目前的这种机制是否可以进行更改,端口要不在启动同步项目启动完成后开放,要不主线程不要依赖项目启动,至少保障访问端口不要一直等待。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值