如何创建多个异步Java过滤器?

mnd*_*mnd 7 java asynchronous servlets filter servlet-filters

我正在尝试创建具有多个异步过滤器的Java应用程序,但似乎无法使它们协同工作。我认为主要问题是在run()方法中,我不知道该如何将请求传递给链中的下一个过滤器。我已经尝试过chain.doFilter(request, response),但这似乎不起作用,并且上有dispatch()complete()API可用AsyncContext,但是这些似乎封闭了整个AsyncContext。似乎必须有另一种方法来使它起作用。以下是我正在使用的过滤器的摘要-第二个过滤器看起来几乎相同。

注意:我正在添加标题以尝试弄清楚正在调用什么。

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
        final AsyncContext asyncContext = request.startAsync();
        final HttpServletResponse res = (HttpServletResponse) response;
        asyncContext.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent event) throws IOException {
                res.addHeader("S-AST2", "onComplete");
            }

            @Override
            public void onTimeout(AsyncEvent event) throws IOException {
                res.addHeader("S-AST3", "onTimeout");
            }

            @Override
            public void onError(AsyncEvent event) throws IOException {
                res.addHeader("S-AST4", "onError");
            }

            @Override
            public void onStartAsync(AsyncEvent event) throws IOException {
                res.addHeader("S-AST0", "onStartAsync");
            }
        });

        asyncContext.start(new Runnable() {
            @Override
            public void run() {
                res.addHeader("S-AST1", "before");
                // This doesn't seem to work...
                asyncContext.dispatch();
                // ... or this ...
                asyncContext.complete();
                // ... or this ...
                chain.doFilter(request, response);
            }
        });
    }
Run Code Online (Sandbox Code Playgroud)

感谢您的见解!

mnd*_*mnd 5

这个答案分为两部分。

1)chain.doFilter(request, response);仍然是必需的。

2)之所以不起作用,是因为在每个过滤器和我正在调用的servlet中request.startAsync(),它启动了一个新的异步过程,而不是使用现有的异步过程。因此,如果过滤器启动了一个异步进程,并且servlet也启动了一个异步进程,它将覆盖/忽略过滤器中启动的一个异步进程。要解决此问题,您必须通过调用来查看异步进程是否已经启动,request.isAsyncStarted()如果不是,则应该使用来获取现有的异步上下文,而不是启动新的异步上下文request.getAsyncContext()。下面是我创建的一个帮助程序类,用于为每个servlet和过滤器执行此操作,因此我可以调用AsyncHelper.getAsyncContext(request, response)它,它将检索现有的AsyncContext或创建一个新的。

public class AsyncHelper {
    public static AsyncContext getAsyncContext(ServletRequest request, ServletResponse response) {
        AsyncContext asyncContext = null;
        if (request.isAsyncStarted()) {
            asyncContext = request.getAsyncContext();
        }
        else {
            asyncContext = request.startAsync(request, response);
            asyncContext.setTimeout(2000);
        }
        return asyncContext;
    }
}
Run Code Online (Sandbox Code Playgroud)