`

Spring mvc callable 异步处理过程Asynchronous Request Processing

 
阅读更多

Spring MVC 3.2 introduced Servlet 3 based asynchronous request processing. Instead of returning a value, as usual, a controller method can now return ajava.util.concurrent.Callable and produce the return value from a Spring MVC managed thread. Meanwhile the main Servlet container thread is exited and released and allowed to process other requests. Spring MVC invokes the Callable in a separate thread with the help of a TaskExecutor and when the Callablereturns, the request is dispatched back to the Servlet container to resume processing using the value returned by the Callable. Here is an example of such a controller method:

@RequestMapping(method=RequestMethod.POST)
public Callable<String> processUpload(final MultipartFile file) {

    return new Callable<String>() {
        public String call() throws Exception {
            // ...
            return "someView";
        }
    };

}

Another option is for the controller method to return an instance of DeferredResult. In this case the return value will also be produced from any thread, i.e. one that is not managed by Spring MVC. For example the result may be produced in response to some external event such as a JMS message, a scheduled task, and so on. Here is an example of such a controller method:

@RequestMapping("/quotes")
@ResponseBody
public DeferredResult<String> quotes() {
    DeferredResult<String> deferredResult = new DeferredResult<String>();
    // Save the deferredResult somewhere..
    return deferredResult;
}

// In some other thread...
deferredResult.setResult(data);

This may be difficult to understand without any knowledge of the Servlet 3.0 asynchronous request processing features. It would certainly help to read up on that. Here are a few basic facts about the underlying mechanism:

  • ServletRequest can be put in asynchronous mode by calling request.startAsync(). The main effect of doing so is that the Servlet, as well as any Filters, can exit but the response will remain open to allow processing to complete later.
  • The call to request.startAsync() returns AsyncContext which can be used for further control over async processing. For example it provides the methoddispatch, that is similar to a forward from the Servlet API except it allows an application to resume request processing on a Servlet container thread.
  • The ServletRequest provides access to the current DispatcherType that can be used to distinguish between processing the initial request, an async dispatch, a forward, and other dispatcher types.

With the above in mind, the following is the sequence of events for async request processing with a Callable:

  • Controller returns a Callable.
  • Spring MVC starts asynchronous processing and submits the Callable to a TaskExecutor for processing in a separate thread.
  • The DispatcherServlet and all Filter’s exit the Servlet container thread but the response remains open.
  • The Callable produces a result and Spring MVC dispatches the request back to the Servlet container to resume processing.
  • The DispatcherServlet is invoked again and processing resumes with the asynchronously produced result from the Callable.

The sequence for DeferredResult is very similar except it’s up to the application to produce the asynchronous result from any thread:

  • Controller returns a DeferredResult and saves it in some in-memory queue or list where it can be accessed.
  • Spring MVC starts async processing.
  • The DispatcherServlet and all configured Filter’s exit the request processing thread but the response remains open.
  • The application sets the DeferredResult from some thread and Spring MVC dispatches the request back to the Servlet container.
  • The DispatcherServlet is invoked again and processing resumes with the asynchronously produced result.

For further background on the motivation for async request processing and when or why to use it please read this blog post series.

Exception Handling for Async Requests

What happens if a Callable returned from a controller method raises an Exception while being executed? The short answer is the same as what happens when a controller method raises an exception. It goes through the regular exception handling mechanism. The longer explanation is that when a Callable raises an Exception Spring MVC dispatches to the Servlet container with the Exception as the result and that leads to resume request processing with the Exception instead of a controller method return value. When using a DeferredResult you have a choice whether to call setResult or setErrorResult with an Exception instance.

Intercepting Async Requests

HandlerInterceptor can also implement AsyncHandlerInterceptor in order to implement the afterConcurrentHandlingStarted callback, which is called instead of postHandle and afterCompletion when asynchronous processing starts.

HandlerInterceptor can also register a CallableProcessingInterceptor or a DeferredResultProcessingInterceptor in order to integrate more deeply with the lifecycle of an asynchronous request and for example handle a timeout event. See the Javadoc of AsyncHandlerInterceptor for more details.

The DeferredResult type also provides methods such as onTimeout(Runnable) and onCompletion(Runnable). See the Javadoc of DeferredResult for more details.

When using a Callable you can wrap it with an instance of WebAsyncTask which also provides registration methods for timeout and completion.

HTTP Streaming

A controller method can use DeferredResult and Callable to produce its return value asynchronously and that can be used to implement techniques such as long polling where the server can push an event to the client as soon as possible.

What if you wanted to push multiple events on a single HTTP response? This is a technique related to "Long Polling" that is known as "HTTP Streaming". Spring MVC makes this possible through the ResponseBodyEmitter return value type which can be used to send multiple Objects, instead of one as is normally the case with@ResponseBody, where each Object sent is written to the response with an HttpMessageConverter.

Here is an example of that:

@RequestMapping("/events")
public ResponseBodyEmitter handle() {
    ResponseBodyEmitter emitter = new ResponseBodyEmitter();
    // Save the emitter somewhere..
    return emitter;
}

// In some other thread
emitter.send("Hello once");

// and again later on
emitter.send("Hello again");

// and done at some point
emitter.complete();

Note that ResponseBodyEmitter can also be used as the body in a ResponseEntity in order to customize the status and headers of the response.

HTTP Streaming With Server-Sent Events

SseEmitter is a sub-class of ResponseBodyEmitter providing support for Server-Sent Events. Server-sent events is a just another variation on the same "HTTP Streaming" technique except events pushed from the server are formatted according to the W3C Server-Sent Events specification.

Server-Sent Events can be used for their intended purpose, that is to push events from the server to clients. It is quite easy to do in Spring MVC and requires simply returning a value of type SseEmitter.

Note however that Internet Explorer does not support Server-Sent Events and that for more advanced web application messaging scenarios such as online games, collaboration, financial applicatinos, and others it’s better to consider Spring’s WebSocket support that includes SockJS-style WebSocket emulation falling back to a very wide range of browsers (including Internet Explorer) and also higher-level messaging patterns for interacting with clients through a publish-subscribe model within a more messaging-centric architecture. For further background on this see the following blog post.

 

HTTP Streaming Directly To The OutputStream

ResponseBodyEmitter allows sending events by writing Objects to the response through an HttpMessageConverter. This is probably the most common case, for example when writing JSON data. However sometimes it is useful to bypass message conversion and write directly to the response OutputStream for example for a file download. This can be done with the help of the StreamingResponseBody return value type.

Here is an example of that:

@RequestMapping("/download")
public StreamingResponseBody handle() {
    return new StreamingResponseBody() {
        @Override
        public void writeTo(OutputStream outputStream) throws IOException {
            // write...
        }
    };
}

Note that StreamingResponseBody can also be used as the body in a ResponseEntity in order to customize the status and headers of the response.

分享到:
评论

相关推荐

    详解spring mvc对异步请求的处理

    Spring MVC通过两种主要方式支持异步处理:`Callable`和`DeferredResult`。这里我们先介绍`Callable`的使用。 #### 2.1 使用`Callable`进行异步处理 在Controller类中,你可以创建返回类型为`Callable`的方法。`...

    spring3.0异步

    Spring提供了`AsyncUncaughtExceptionHandler`来捕获并处理异步方法抛出的未被捕获异常。此外,通过`@EnableAsync`配置的`Executor`,我们可以调整线程池大小、队列容量等参数以优化性能。 ### 6. 性能优化 异步...

    spring mvc 4.0.3

    5. **异步处理**:Spring MVC 4引入了异步处理能力,允许控制器方法返回一个`Callable`或`DeferredResult`对象,从而支持非阻塞I/O,提高了系统性能。 6. **WebSocket支持**:此版本开始集成WebSocket技术,通过...

    spring 3.1 mvc sample

    3. **Async Support**:引入了异步处理能力,允许Controller方法返回DeferredResult或Callable对象,这样可以在不阻塞线程的情况下执行耗时操作,提高系统性能。 4. **Expression Language (EL)**:Spring 3.1支持...

    看透springMvc源代码分析与实践

    22.1.1 Servlet 3.0处理异步请求实例282 22.1.2 异步请求监听器Async-Listener284 22.2 Spring MVC中的异步请求286 22.2.1 Spring MVC中异步请求相关组件286 22.2.2 Spring MVC对异步请求的支持297 22.2.3 ...

    SpringMvc笔记(第12次)1

    在官方文档中(1.7.1章节),可以看到Spring MVC提供了两种方式来处理异步请求:`CompletableFuture`和`Callable`。这两种方式都可以帮助我们实现非阻塞的异步处理。 10. 当我们使用Spring MVC进行异步请求实战时,...

    Spring注解驱动开发实战-springMVC

    综上所述,Spring MVC的注解驱动开发为我们提供了强大的功能,可以轻松地进行ServletContext组件的注册、自定义框架行为以及处理异步请求。通过熟练掌握这些知识点,我们可以构建出高效、灵活的Web应用。同时,不断...

    springmvc4.0的jar包

    8. **异步处理**:Spring MVC 4.0引入了异步处理能力,允许控制器方法返回DeferredResult或Callable,这样服务器可以在执行耗时操作时释放线程,提高系统并发能力。 9. **数据绑定与验证**:通过@Valid注解和...

    springmvcinaction:用于spring mvc源代码-mvc source code

    - Spring MVC 支持异步请求处理,可以返回 DeferredResult 或 Callable 对象。 7. **RESTful 风格** - 使用 @RequestMapping 和 HTTP 动词(GET、POST、PUT、DELETE 等)实现 RESTful API。 通过阅读和研究 ...

    springMvc学习相关jar包

    15. **异步处理**:Spring MVC 提供了异步请求处理功能,可以返回 Callable 或 DeferredResult,实现在后台线程中执行耗时操作。 16. **集成其他技术**:Spring MVC 可以很好地与 Spring Data、MyBatis、Hibernate ...

    spring-web-3.1.1.RELEASE.jar.zip

    2. 异步处理支持:引入了异步请求处理,允许控制器方法返回`Callable`或`DeferredResult`,从而实现非阻塞式的处理。 3. WebSocket支持:提供了WebSocket API,可以实现双向通信,适用于实时数据传输的应用场景。 4....

    springmvc处理异步请求的示例

    在Spring MVC中,有两种主要的方式来实现异步请求处理:`Callable` 和 `DeferredResult`。 1. **Callable**: 当控制器方法返回一个`Callable&lt;T&gt;`对象时,Spring MVC会启动一个新的线程来执行这个Callable,主线程...

    org.springframework.web.servlet-3.1.0.RELEASE.jar.zip

    10. **Async Support**:3.1版本引入了异步处理的支持,使得Controller方法可以返回一个DeferredResult或Callable,从而支持非阻塞I/O和异步任务处理。 在实际开发中,开发者还需要了解如何配置Spring Web MVC,...

    spring-4.2.2和springMVC4.2.2

    2. 异步方法支持:Spring MVC引入了更强大的异步处理能力,允许控制器方法返回`Callable`或`DeferredResult`,以便在后台执行任务而不会阻塞线程池。 3. WebSocket增强:Spring 4.2.2增强了WebSocket的支持,包括...

    异步Web方法调用例子-Java源码

    - **JAX-WS的AsyncHandler**:在基于JAX-WS的Web服务中,可以定义AsyncHandler来处理异步响应。 - **Apache CXF的AsyncClient**:CXF提供了对异步调用的支持,可以创建异步客户端来调用Web服务。 3. **AXIS2与...

    spring mybatis 调用oracle存储过程

    通过以上步骤,开发者可以在Spring和MyBatis环境中顺利地调用Oracle存储过程,实现复杂业务逻辑的处理。这不仅可以提高代码的可维护性,还能利用数据库的优势来优化性能。在进行这类操作时,一定要注意参数类型、...

    详解SpringBoot中异步请求和异步调用(看完这一篇就够了)

    然后,需要设置异步上下文的监听器,以便处理异步请求的开始、完成、异常和超时等事件。最后,需要在异步线程中执行耗时的处理操作,并在处理完成后通知异步上下文,以便释放资源。 方式二:使用Callable方式实现...

    Spring Boot 异步框架的使用详解

    在Spring Boot中,异步处理是一种提升应用性能的关键技术,尤其在处理大量并发请求时。本文将深入讲解Spring Boot异步框架的使用,帮助开发者更好地理解和利用这一特性。 首先,异步处理能够显著提高应用响应速度,...

    WebAsyncTask:WebAsyncTask异步任务样例工程---spring bootspring

    Spring的WebAsyncTask是基于Servlet 3.0的Asynchronous Request Processing特性实现的。它提供了一个灵活的API,允许开发者定义异步任务的执行逻辑,同时可以设置超时、回调和错误处理策略。WebAsyncTask的核心是`...

    java代码实现异步调用代码

    7. **Spring框架中的异步处理** - **@Async注解**:Spring框架提供了`@Async`注解,可以轻松地使方法异步执行,配合`AsyncConfigurer`接口可以自定义线程池。 - **AsyncResult**:Spring的AsyncResult类用于表示...

Global site tag (gtag.js) - Google Analytics