簡體   English   中英

Tomcat 濾波器不支持異步

[英]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

ServletRequestServletResponseFilterChain object 僅在調用doFilter的線程上有效。 如果要異步使用它們,則需要啟用異步處理(參見Jakarta EE 教程)。

ServletRequest.startAsync()ServletRequestServletResponse置於異步模式,但FilterChain只能在原線程上使用:

service方法需要與應用於 servlet 的所有過濾器在同一線程中運行。

(參見Servlet 規范

因此,您需要進行以下操作:

  1. 請求通過過濾器時,您調用ServletRequest.startAsync()並啟動新線程或使用任何其他執行器進行異步過濾(例如AsyncContext.start(Runnable) ),
  2. 異步任務完成后,將結果寫入請求屬性並調用AsyncContext.dispatch() :這將從頭開始重新啟動過濾器鏈,
  3. 當再次調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM