繁体   English   中英

如何在spring mvc中使用servlet 3.1?

[英]How to use servlet 3.1 in spring mvc?

有2种不同的功能:

  1. servlet 3.0允许在与容器线程不同的线程中处理请求。

  2. servlet 3.1允许读/写socket而不阻塞读/写线程

互联网上有很多关于servlet 3.0功能的例子。 我们可以很容易地在Spring中使用它。 我们只需要返回DefferedResultCompletableFuture

但我在春天找不到使用servlet 3.1的例子。 据我所知,我们必须注册WriteListenerReadListener并在内部进行圆顶脏工作。 但我找不到那个听众的例子。 我相信这不容易。

能否请你在春天提供servlet 3.1功能的例子,并附上Listener实现的解释?

对于servlet 3.1,您可以使用Reactive Streams桥支持非阻塞I / O.

Servlet 3.1+容器

要将WAR部署为任何Servlet 3.1+容器,您可以在WAR中扩展并包含{api-spring-framework} /web/server/adapter/AbstractReactiveWebInitializer.html [AbstractReactiveWebInitializer]。 该类用ServletHttpHandlerAdapter包装一个HttpHandler并将其注册为Servlet。

所以你应该扩展AbstractReactiveWebInitializer ,它正在添加异步支持

 registration.setAsyncSupported(true); 

并且支持ServletHttpHandlerAdapter

 AsyncContext asyncContext = request.startAsync(); 

如果您正在寻找Spring / Servlet 3.1非阻塞HTTP API声明的示例,请尝试以下操作:

@GetMapping(value = "/asyncNonBlockingRequestProcessing")
public CompletableFuture<String> asyncNonBlockingRequestProcessing(){
        ListenableFuture<String> listenableFuture = getRequest.execute(new AsyncCompletionHandler<String>() {
            @Override
            public String onCompleted(Response response) throws Exception {
                logger.debug("Async Non Blocking Request processing completed");
                return "Async Non blocking...";
             }
        });
        return listenableFuture.toCompletableFuture();
}

在Servlet容器级别需要Spring Web 5.0+和Servlet 3.1支持(Tomcat 8.5 +,Jetty 9.4 +,WildFly 10+)

不应该太难追查一些例子。 我在IBM的WASdev / sample.javaee7.servlet.nonblocking找到了一个。 在Spring或Spring Boot中使用javax.servlet API只是要求Spring注入HttpServletRequestHttpServletResponse 所以,一个简单的例子可能是:

@SpringBootApplication
@Controller
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @RequestMapping(path = "")
    public void writeStream(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ServletOutputStream output = response.getOutputStream();
        AsyncContext context = request.startAsync();
        output.setWriteListener(new WriteListener() {
            @Override
            public void onWritePossible() throws IOException {
                if ( output.isReady() ) {
                    output.println("WriteListener:onWritePossible() called to send response data on thread : " + Thread.currentThread().getName());
                }
                context.complete();
            }
            @Override
            public void onError(Throwable t) {
                context.complete();
            }
        });
    }
}

这只是创建一个WriteListener并将其附加到请求输出流然后返回。 没有什么花哨。

编辑:重点是servlet容器(例如Tomcat)在无阻塞地写入数据时调用onWritePossible 有关使用Servlet 3.1的非阻塞I / O的更多信息:使用Java EE 7的可扩展应用程序(TOTD#188)。

侦听器(和编写器)具有回调方法,当内容可供读取或可以无阻塞地写入时调用这些方法。

因此onWritePossible仅在out.println可以不受阻塞地调用时被调用。

调用setXXXListener方法表示使用非阻塞I / O而不是传统I / O.

大概你要做的就是检查output.isReady以了解你是否可以继续写字节。 似乎你必须与发送者/接收者就块大小达成某种隐含的协议。 我从来没有使用它,所以我不知道,但是你在Spring框架中要求提供一个这样的例子,那就是提供的内容。

因此onWritePossible仅在out.println可以不受阻塞地调用时被调用。 这听起来不错,但我怎么能理解可写多少字节? 我该怎么控制呢?

编辑2:这是一个非常好的问题,我不能给你一个确切的答案。 我假设当服务器在主servlet的单独(异步)线程中执行代码时,会调用onWritePossible 从示例中检查input.isReady()output.isReady() ,我假设阻塞您的线程,直到发送方/接收方准备好更多。 由于这是异步完成的,因此服务器本身不会被阻止,并且可以处理其他请求。 我从来没有用过这个,所以我不是专家。

当我说与发送器/接收器有关于块大小的某种隐含协议时,这意味着如果接收器能够接受1024字节块,那么当output.isReady为true时,您将写入该量。 你必须通过阅读文档来了解这一点,关于它的api中没有任何内容。 否则你可以写单个字节,但oracle的例子使用1024字节块。 1024字节块是用于流式I / O的相当标准的块大小。 上面的例子必须扩展为在while循环中写入字节,就像在oracle示例中所示。 这是一个留给读者的练习。

项目反应堆和Spring Webflux具有backpressure概念,可以更仔细地解决这个问题。 这将是一个单独的问题,我没有仔细研究这对夫妇的发送者和接收者(反之亦然)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM