是的,可以将 ReadListeners 与 Spring 的 DeferredResult 一起使用,我将在下面概述该过程。我想 WriteListeners 的过程是相似的。
开始异步处理
当 Spring 将 DeferredResult 视为返回类型时,WebAsyncManager 将在您的方法执行后调用 request.startAsync()。这将以异步模式启动请求处理。重要的是不要在控制器方法中手动启动异步处理,Spring 无法应对已经启动的异步处理,并且会抛出异常。
附加您的 ReadListener
这将因容器而异。在异步处理开始之前,Jetty 将允许您在控制器方法中将 readListener 附加到 ServletInputStream:
DeferredResult<String> deferredResult = new DeferredResult<String>();
ReadListener readListener = new NioReadListener(request, deferredResult, modelMap);
ServletInputStream stream = request.getInputStream();
stream.setReadListener(readListener);
Tomcat,也许还有其他容器也不允许这样做。他们对 Servlet 规范的解释是,必须在允许附加 ReadListener 之前启动异步处理。因此,如果您希望您的应用程序与容器无关,我建议使用以下技术。
创建一个 DeferredResultProcessingInterceptor
Spring 提供了一种使用 DeferredResultProcessingInterceptors 来拦截异步请求处理的机制。如下创建拦截器:
/**
* Responsible for attaching a {@link NioReadListener} to the servlet input stream before async processing begins.
*/
public class NioDeferredResultInterceptor extends DeferredResultProcessingInterceptorAdapter {
private final DeferredResult<String> _deferredResult;
private final VaultServletRequest _request;
private final ModelMap _model;
public NioDeferredResultInterceptor(ServletRequest request, DeferredResult<String> deferredResult, ModelMap model) {
_deferredResult = deferredResult;
_request = request;
_model = model;
}
@Override
public <T> void preProcess(NativeWebRequest request, DeferredResult<T> deferredResult) throws Exception {
ReadListener readListener = new NioReadListener(_request, _deferredResult, _model);
ServletInputStream servletInputStream = _request.getInputStream();
servletInputStream.setReadListener(readListener);
}
preProcess 方法将在 Spring 开始异步处理之后立即执行,但在其他任何事情发生之前,这正是我们想要的。
DeferredResultProcessingInterceptor 可以在您的控制器方法中附加到您的请求,如下所示:
DeferredResultProcessingInterceptor deferredResultInterceptor =
new NioDeferredResultInterceptor(request, deferredResult, modelMap);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerDeferredResultInterceptor("SomeKey", deferredResultInterceptor);