【问题标题】:Is Servlet 3.1 (Read|Write)Listener supported by DeferredResult in Spring 4?Spring 4 中的 DeferredResult 是否支持 Servlet 3.1 (Read|Write)Listener?
【发布时间】:2015-05-03 21:36:58
【问题描述】:

我正在阅读 JayWay article 关于 Servlet with Spring 的异步支持。

有趣的是:

如果您的服务预计会接收大量请求或响应主体,尤其是客户端写入或读取速度较慢时,您将受益于使用 Servlet 3.1 中引入的非阻塞 IO 功能,如前所述。在 ServletInputStream 上有 setReadListener 方法,您可以在其中设置 ReadListener。

我看到您可以使用 DeferredResult 异步启动 servlet,但我找不到与 ReadListenerWriteListener 相关的任何信息。

或者至少,我期望在那方面有一些东西,因为它在我的应用程序的边界上很友好,我只需要获取请求并发送结果。

【问题讨论】:

    标签: java spring spring-mvc servlets


    【解决方案1】:

    是的,可以将 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); 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-14
      • 1970-01-01
      • 2014-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-11
      • 1970-01-01
      相关资源
      最近更新 更多