为了账号安全,请及时绑定邮箱和手机立即绑定

如何在 spring mvc 中使用 servlet 3.1?

如何在 spring mvc 中使用 servlet 3.1?

qq_笑_17 2023-03-02 10:02:19
有 2 种不同的功能可用:servlet 3.0允许在不同于容器线程的线程中处理请求。servlet 3.1允许在不阻塞读/写线程的情况下读/写套接字网上有很多关于 servlet 3.0 特性的例子。我们可以很容易地在Spring中使用它。我们只需要返回DefferedResult或CompletableFuture但是我找不到 spring 中使用 servlet 3.1 的示例。据我所知,我们必须登记WriteListener并ReadListener在里面做一些肮脏的工作。但是我找不到那个听众的例子。我相信这不是很容易。您能否提供 spring 中 servlet 3.1 功能的示例以及 Listener implementaion 的解释?
查看完整描述

4 回答

?
三国纷争

TA贡献1804条经验 获得超7个赞

对于 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();


查看完整回答
反对 回复 2023-03-02
?
慕桂英3389331

TA贡献2036条经验 获得超8个赞

追查一些例子不应该太难。我在WASdev/sample.javaee7.servlet.nonblocking找到了来自 IBM 的一个。在 Spring 或 Spring Boot 中使用javax.servletAPI 只是要求 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在可以无阻塞地写入数据时调用。有关更多信息,请参见使用 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:这是一个非常好的问题,我无法给你一个确切的答案。我假设onWritePossible当服务器在与主 servlet 分开的(异步)线程中执行代码时调用它。从您检查的示例中,input.isReady()或者output.isReady()我假设它会阻塞您的线程,直到发送方/接收方准备好接收更多消息。由于这是异步完成的,服务器本身不会被阻塞并且可以处理其他请求。我从来没有用过这个,所以我不是专家。


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


Project reactor 和 Spring Webflux 的概念backpressure可能会更仔细地解决这个问题。那将是一个单独的问题,我没有仔细研究发送者和接收者是如何结合的(反之亦然)。


查看完整回答
反对 回复 2023-03-02
?
皈依舞

TA贡献1851条经验 获得超3个赞

Servlet 3.0 - 解耦容器线程和处理线程。返回 DeferredResult 或 CompletableFuture。所以控制器处理可以在与服务器请求处理线程不同的线程中。服务器线程池可以自由处理更多传入请求。

但是,IO 仍然处于阻塞状态。读取和写入输入和输出流(接收和发送对慢速客户端的响应)。

Servlet 3.1 - 一路非阻塞,包括 IO。直接在 Spring 上使用 Servlet 3.1 意味着你必须使用ReadListenerWriteListener接口,太麻烦了。此外,您必须避免使用同步和阻塞的 Servlet API,例如 Servlet 和 Filter。使用 Spring Webflux,它使用 Reactive Streams API 并支持 Servlet 3.1。


查看完整回答
反对 回复 2023-03-02
?
慕村225694

TA贡献1880条经验 获得超4个赞

如果您正在寻找 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+)


查看完整回答
反对 回复 2023-03-02
  • 4 回答
  • 0 关注
  • 112 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信