Java 如何在SpringMVC中使用Servlet3.1?

Java 如何在SpringMVC中使用Servlet3.1?,java,spring-boot,spring-mvc,nio,servlet-3.1,Java,Spring Boot,Spring Mvc,Nio,Servlet 3.1,有两种不同的功能可用: servlet 3.0允许在不同于容器线程的线程中处理请求 servlet 3.1允许在不阻塞读/写线程的情况下读/写套接字 互联网上有很多关于Servlet3.0特性的例子。我们可以在春天很容易地使用它。我们只需返回DefferedResult或CompletableFuture 但我找不到在spring中使用Servlet3.1的示例。据我所知,我们必须注册WriteListener和ReadListener并在里面做一些肮脏的工作。但我找不到听众的例子。我相信这并不

有两种不同的功能可用:

  • servlet 3.0允许在不同于容器线程的线程中处理请求

  • servlet 3.1允许在不阻塞读/写线程的情况下读/写套接字

  • 互联网上有很多关于Servlet3.0特性的例子。我们可以在春天很容易地使用它。我们只需返回
    DefferedResult
    CompletableFuture

    但我找不到在spring中使用Servlet3.1的示例。据我所知,我们必须注册
    WriteListener
    ReadListener
    并在里面做一些肮脏的工作。但我找不到听众的例子。我相信这并不容易


    您能否提供spring中servlet 3.1功能的示例,并解释侦听器实现?

    如果您正在寻找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();
    }
    
    @GetMapping(value=“/asyncNonBlockingRequestProcessing”)
    公共CompletableFuture asyncNonBlockingRequestProcessing(){
    ListenableFuture ListenableFuture=getRequest.execute(新的AsyncCompletionHandler(){
    @凌驾
    未完成的公共字符串(响应)引发异常{
    debug(“异步非阻塞请求处理完成”);
    返回“异步非阻塞…”;
    }
    });
    返回listenableFuture.toCompletableFuture();
    }
    

    在Servlet容器级别需要SpringWeb5.0+和Servlet3.1支持(Tomcat8.5+、Jetty 9.4+、WildFly 10+)

    不难找到一些示例。我在IBM找到了一个。在Spring或Spring Boot中使用
    javax.servlet
    API只需请求Spring注入
    HttpServletRequest
    HttpServletResponse
    。因此,一个简单的例子可以是:

    @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
    。更多关于这方面的信息,请访问

    侦听器(和写入器)具有回调方法,当内容可供读取或可在无阻塞的情况下写入时调用这些方法

    因此,只有当
    out时才会调用
    onWritePossible
    。可以在不阻塞的情况下调用println

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

    大概您需要做的是检查
    output.isReady
    ,以了解是否可以继续写入字节。似乎您必须与发送方/接收方就块大小达成某种隐式协议。我从未使用过它,所以我不知道,但您要求在Spring框架中提供一个这样的示例,这就是我们提供的

    因此只有在out时才调用onWritePossible。println可以在没有阻塞的情况下调用。这听起来是正确的,但我如何理解可以写入多少字节?我该如何控制这一切

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

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


    Project reactor和Spring Webflux采用了背压的概念,可以更仔细地解决这个问题。这将是一个单独的问题,我还没有仔细研究如何将发送者和接收者结合在一起(反之亦然)。

    对于servlet 3.1,您可以通过使用反应流桥来支持它

    Servlet 3.1+容器

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

    所以您应该扩展它,添加异步支持

    以及政府的支持


    我的建议是这样的,我有正确的建议,但我想知道更多关于替代品的信息。我问这个问题是因为我想知道为什么WebFlux比纯servlet 3.1更好,你能评论一下这段代码吗?这对我来说是不透明的,为什么代码是非阻塞的。我也不明白那段代码的作用,但是你的监听器只是一个存根,什么都不做,它写入流并关闭它。你认为它应该做什么
    output.println(“调用WriteListener:onWritePossible()以发送线程上的响应数据:“+thread.currentThread().getName()”)来自WriteListener的文档-“当可以在不阻塞的情况下写入数据时调用。容器将第一次调用此方法
    
    registration.setAsyncSupported(true);
    
    AsyncContext asyncContext = request.startAsync();