我在catalina日志中具有以下堆栈跟踪:
24-Jan-2019 16:44:13.139 INFO [messageBrokerScheduler-3] org.apache.coyote.AbstractProcessor.setErrorState An error occurred in processing while on a non-container thread. The connection will be closed immediately
java.io.IOException: An existing connection was forcibly closed by the remote host
at sun.nio.ch.SocketDispatcher.write0(Native Method)
.....
at org.apache.catalina.connector.ResponseFacade.flushBuffer(ResponseFacade.java:312)
at org.springframework.http.server.ServletServerHttpResponse.flush(ServletServerHttpResponse.java:96)
at org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession.writeFrameInternal(AbstractHttpSockJsSession.java:350)
at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.writeFrame(AbstractSockJsSession.java:322)
at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.sendHeartbeat(AbstractSockJsSession.java:255)
at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession$HeartbeatTask.run(AbstractSockJsSession.java:456)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
从堆栈跟踪中可以看出,AbstractSockJsSession $ HeartbeatTask.run(AbstractSockJsSession.java:456)中有一个例外
从spring-websocket源代码中,我们有以下内容:
private class HeartbeatTask implements Runnable {
private boolean expired;
@Override
public void run() {
synchronized (responseLock) {
if (!this.expired && !isClosed()) {
try {
sendHeartbeat();
}
catch (Throwable ex) {
// Ignore: already handled in writeFrame...
}
finally {
this.expired = true;
}
}
}
}
void cancel() {
this.expired = true;
}
}
可以看出,sendHeartbeat()方法由try-catch块包装。
所以,不明白,tomcat如何打印该异常?
我正在使用spring-websocket 4.3.8,tomcat 8.5.9
JFYI:
我知道spring-websocket 4.3.8版本中添加了catch块,这就是为什么我使用4.3.8的原因
我也知道在Tomcat 8.5.25中,setErrorState以调试模式记录消息。