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并在里面做一些肮脏的工作。但我找不到听众的例子。我相信这并不
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();