[英]Tomcat filter does not support asynchrony
比如标题
@WebFilter("/*")
@Component
@Slf4j
public class FilterDemo1 implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException, IOException {
new Thread(() -> {
try {
chain.doFilter(req, resp);
} catch (Exception e) {
log.error("a", e);
}
}).start();
}
}
因此,如果Tomcat过滤器中有耗时任务(如RPC或HTTP),则必须等待,不能异步
java.lang.NullPointerException: null
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.27.jar:9.0.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.27.jar:9.0.27]```
[error][1]
[1]: https://i.stack.imgur.com/tFYTH.png
ServletRequest
、 ServletResponse
和FilterChain
object 仅在调用doFilter
的线程上有效。 如果要异步使用它们,则需要启用异步处理(参见Jakarta EE 教程)。
ServletRequest.startAsync()
将ServletRequest
和ServletResponse
置于异步模式,但FilterChain
只能在原线程上使用:
service
方法需要与应用于 servlet 的所有过滤器在同一线程中运行。
(参见Servlet 规范)
因此,您需要进行以下操作:
ServletRequest.startAsync()
并启动新线程或使用任何其他执行器进行异步过滤(例如AsyncContext.start(Runnable)
),AsyncContext.dispatch()
:这将从头开始重新启动过滤器链,doFilter
时,您使用请求的属性来执行您的过滤逻辑并调用FilterChain.doFilter
例如,您可以使用以下内容:
@WebFilter(asyncSupported = true, urlPatterns = {"/*"}, dispatcherTypes = {DispatcherType.ASYNC, DispatcherType.REQUEST})
public class Filter1 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
switch (request.getDispatcherType()) {
case REQUEST :
// First pass: start asynchronous processing
final AsyncContext asyncContext = request.startAsync();
new Thread(() -> {
try {
Thread.currentThread().sleep(5000);
} catch (Exception e) {
request.setAttribute("filter1Error", e);
}
asyncContext.dispatch();
}).start();
break;
case ASYNC :
// Second pass: throw or forward
Exception e = (Exception) request.getAttribute("filter1Error");
if (e instanceof IOException) {
throw (IOException) e;
} else if (e instanceof ServletException) {
throw (ServletException) e;
} else if (e != null) {
throw new ServletException(e);
}
chain.doFilter(request, response);
break;
default :
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.