`
234390216
  • 浏览: 10237906 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
博客专栏
A5ee55b9-a463-3d09-9c78-0c0cf33198cd
Oracle基础
浏览量:462838
Ad26f909-6440-35a9-b4e9-9aea825bd38e
springMVC介绍
浏览量:1775912
Ce363057-ae4d-3ee1-bb46-e7b51a722a4b
Mybatis简介
浏览量:1398690
Bdeb91ad-cf8a-3fe9-942a-3710073b4000
Spring整合JMS
浏览量:395130
5cbbde67-7cd5-313c-95c2-4185389601e7
Ehcache简介
浏览量:680150
Cc1c0708-ccc2-3d20-ba47-d40e04440682
Cas简介
浏览量:531108
51592fc3-854c-34f4-9eff-cb82d993ab3a
Spring Securi...
浏览量:1184883
23e1c30e-ef8c-3702-aa3c-e83277ffca91
Spring基础知识
浏览量:468680
4af1c81c-eb9d-365f-b759-07685a32156e
Spring Aop介绍
浏览量:151478
2f926891-9e7a-3ce2-a074-3acb2aaf2584
JAXB简介
浏览量:68321
社区版块
存档分类
最新评论

SpringMVC对Servlet3异步请求的支持

阅读更多

SpringMVC对Servlet3异步请求的支持

SpringMVC对Servlet3异步请求的支持有两种方式,分别是通过处理器方法返回Callable和DeferredResult。按照Servlet3的规范,支持异步请求时需要配置对应的Servlet和Filter支持异步请求,为了使SpringMVC支持异步请求的处理,需要在定义DispatcherServlet时配置其支持异步请求,在DispatcherServlet之前定义的Filter也需要配置支持异步请求。

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <!-- 启用异步支持 -->
    <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

返回Callable

当处理器的返回方法是Callable类型时会默认发起异步请求,并使用一个TaskExecutor来调用返回的Callable,之后的处理就跟正常的SpringMVC请求是一样的。Callable的返回结果也跟正常请求SpringMVC的一样,可以返回Model、ModelAndView、String、Object等,也可以结合@ResponseBody使用,具体可以参考CallableMethodReturnValueHandlerhandleReturnValue()

    @RequestMapping("/callable")
    public Callable<String> forCallable(Model model) throws Exception {
        return () -> {
            TimeUnit.SECONDS.sleep(1);//睡眠1秒,模仿某些业务操作
            model.addAttribute("a", "aaaaaaa");
            return "async_request_callable";
        };
    }

如果需要针对于单个Callable请求指定超时时间,我们可以把Callable用一个WebAsyncTask包裹起来。然后还可以指定超时回调和正常处理完成的回调。

    @RequestMapping("/callable/timeout")
    public WebAsyncTask<String> forCallableWithTimeout(Model model) throws Exception {
        long timeout = 5 * 1000L;
        WebAsyncTask<String> asyncTask = new WebAsyncTask<>(timeout, () -> {
            TimeUnit.MILLISECONDS.sleep(timeout + 10);
            model.addAttribute("a", "aaaaaaa");
            return "async_request_callable";
        });
        asyncTask.onTimeout(() -> {
            System.out.println("响应超时回调");
            return "async_request_callable_timeout";
        });
        asyncTask.onCompletion(() -> {
            System.out.println("响应callable调用完成的回调");
        });
        return asyncTask;
    }

返回DeferredResult

使用DeferredResult的返回结果的编程通常是在处理器方法中创建一个DeferredResult实例,把它保存起来后再进行返回,比如保存到一个队列中,然后在另外的一个线程中会从这个队列中拿到相应的DeferredResult对象进行相应的业务处理后会往DeferredResult中设置对应的返回值。返回了DeferredResult后SpringMVC将创建一个DeferredResultHandler用于监听DeferredResult,一旦DeferredResult中设置了返回值后,DeferredResultHandler就将对返回值进行处理。DeferredResult的处理过程见DeferredResultMethodReturnValueHandlerhandleReturnValue()

@RequestMapping("/deferredresult")
public DeferredResult<String> forDeferredResult() throws Exception {
    DeferredResult<String> result = new DeferredResult<>();
    new Thread(() -> {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result.setResult("async_request_deferredresult");
    }).start();
    return result;
}

对于DeferredResult也是可以单独指定超时时间和超时后的回调的,它的超时时间可以直接通过构造函数传递,单位是毫秒。

@RequestMapping("/deferredresult/timeout")
public DeferredResult<String> forDeferredResultWithTimeout() throws Exception {
    DeferredResult<String> result = new DeferredResult<>(10 * 1000);
    new Thread(() -> {
        try {
            TimeUnit.SECONDS.sleep(31);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result.setResult("async_request_deferredresult");
    }).start();
    
    result.onTimeout(() -> {
        System.out.println("响应超时回调函数");
    });
    
    result.onCompletion(() -> {
        System.out.println("响应完成的回调函数");
    });
    
    return result;
}

配置

可以通过<mvc:annotation-driven/>的子元素<mvc:async-support/>来定义处理异步请求默认的超时时间和需要使用的TaskExecutor。如果不指定默认超时时间则默认会使用容器的异步请求超时时间,如果不指定需要使用的TaskExecutor,则默认会使用一个SimpleAsyncTaskExecutor。在下面的配置中我们就配置了默认的超时时间是15秒,且处理异步请求的TaskExecutor是bean容器中名为asyncTaskExecutor的TaskExecutor。

<mvc:annotation-driven>
    <mvc:async-support default-timeout="15000" task-executor="asyncTaskExecutor"/>
</mvc:annotation-driven>

拦截器

返回Callable类型的请求可以通过实现CallableProcessingInterceptor接口自定义一个拦截器来拦截,也可以通过继承CallableProcessingInterceptorAdapter抽象类来定义拦截器,这样就只需要选择自己感兴趣的方法进行实现。CallableProcessingInterceptor接口定义如下:

public interface CallableProcessingInterceptor {

	static final Object RESULT_NONE = new Object();

	static final Object RESPONSE_HANDLED = new Object();

	/**
	 * Invoked <em>before</em> the start of concurrent handling in the original
	 * thread in which the {@code Callable} is submitted for concurrent handling.
	 *
	 * <p>
	 * This is useful for capturing the state of the current thread just prior to
	 * invoking the {@link Callable}. Once the state is captured, it can then be
	 * transferred to the new {@link Thread} in
	 * {@link #preProcess(NativeWebRequest, Callable)}. Capturing the state of
	 * Spring Security's SecurityContextHolder and migrating it to the new Thread
	 * is a concrete example of where this is useful.
	 * </p>
	 *
	 * @param request the current request
	 * @param task the task for the current async request
	 * @throws Exception in case of errors
	 */
	<T> void  beforeConcurrentHandling(NativeWebRequest request, Callable<T> task) throws Exception;

	/**
	 * Invoked <em>after</em> the start of concurrent handling in the async
	 * thread in which the {@code Callable} is executed and <em>before</em> the
	 * actual invocation of the {@code Callable}.
	 *
	 * @param request the current request
	 * @param task the task for the current async request
	 * @throws Exception in case of errors
	 */
	<T> void preProcess(NativeWebRequest request, Callable<T> task) throws Exception;

	/**
	 * Invoked <em>after</em> the {@code Callable} has produced a result in the
	 * async thread in which the {@code Callable} is executed. This method may
	 * be invoked later than {@code afterTimeout} or {@code afterCompletion}
	 * depending on when the {@code Callable} finishes processing.
	 *
	 * @param request the current request
	 * @param task the task for the current async request
	 * @param concurrentResult the result of concurrent processing, which could
	 * be a {@link Throwable} if the {@code Callable} raised an exception
	 * @throws Exception in case of errors
	 */
	<T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) throws Exception;

	/**
	 * Invoked from a container thread when the async request times out before
	 * the {@code Callable} task completes. Implementations may return a value,
	 * including an {@link Exception}, to use instead of the value the
	 * {@link Callable} did not return in time.
	 *
	 * @param request the current request
	 * @param task the task for the current async request
	 * @return a concurrent result value; if the value is anything other than
	 * {@link #RESULT_NONE} or {@link #RESPONSE_HANDLED}, concurrent processing
	 * is resumed and subsequent interceptors are not invoked
	 * @throws Exception in case of errors
	 */
	<T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception;

	/**
	 * Invoked from a container thread when async processing completes for any
	 * reason including timeout or network error.
	 *
	 * @param request the current request
	 * @param task the task for the current async request
	 * @throws Exception in case of errors
	 */
	<T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception;

}

它的配置是通过<mvc:callable-interceptors/>配置的。

<mvc:annotation-driven>
    <mvc:async-support default-timeout="15000" task-executor="asyncTaskExecutor">
        <mvc:callable-interceptors>
            <bean class="YourCallableProcessingInterceptor"/>
        </mvc:callable-interceptors>
    </mvc:async-support>
</mvc:annotation-driven>

返回DeferredResult的也可以进行拦截,这需要我们实现DeferredResultProcessingInterceptor接口或者继承自DeferredResultProcessingInterceptorAdapterDeferredResultProcessingInterceptor接口定义如下:

public interface DeferredResultProcessingInterceptor {

	/**
	 * Invoked immediately before the start of concurrent handling, in the same
	 * thread that started it. This method may be used to capture state just prior
	 * to the start of concurrent processing with the given {@code DeferredResult}.
	 *
	 * @param request the current request
	 * @param deferredResult the DeferredResult for the current request
	 * @throws Exception in case of errors
	 */
	<T> void  beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult) throws Exception;

	/**
	 * Invoked immediately after the start of concurrent handling, in the same
	 * thread that started it. This method may be used to detect the start of
	 * concurrent processing with the given {@code DeferredResult}.
	 *
	 * <p>The {@code DeferredResult} may have already been set, for example at
	 * the time of its creation or by another thread.
	 *
	 * @param request the current request
	 * @param deferredResult the DeferredResult for the current request
	 * @throws Exception in case of errors
	 */
	<T> void preProcess(NativeWebRequest request, DeferredResult<T> deferredResult) throws Exception;

	/**
	 * Invoked after a {@code DeferredResult} has been set, via
	 * {@link DeferredResult#setResult(Object)} or
	 * {@link DeferredResult#setErrorResult(Object)}, and is also ready to
	 * handle the concurrent result.
	 *
	 * <p>This method may also be invoked after a timeout when the
	 * {@code DeferredResult} was created with a constructor accepting a default
	 * timeout result.
	 *
	 * @param request the current request
	 * @param deferredResult the DeferredResult for the current request
	 * @param concurrentResult the result to which the {@code DeferredResult}
	 * @throws Exception in case of errors
	 */
	<T> void postProcess(NativeWebRequest request, DeferredResult<T> deferredResult, Object concurrentResult) throws Exception;

	/**
	 * Invoked from a container thread when an async request times out before
	 * the {@code DeferredResult} has been set. Implementations may invoke
	 * {@link DeferredResult#setResult(Object) setResult} or
	 * {@link DeferredResult#setErrorResult(Object) setErrorResult} to resume processing.
	 *
	 * @param request the current request
	 * @param deferredResult the DeferredResult for the current request; if the
	 * {@code DeferredResult} is set, then concurrent processing is resumed and
	 * subsequent interceptors are not invoked
	 * @return {@code true} if processing should continue, or {@code false} if
	 * other interceptors should not be invoked
	 * @throws Exception in case of errors
	 */
	<T> boolean handleTimeout(NativeWebRequest request, DeferredResult<T> deferredResult) throws Exception;

	/**
	 * Invoked from a container thread when an async request completed for any
	 * reason including timeout and network error. This method is useful for
	 * detecting that a {@code DeferredResult} instance is no longer usable.
	 *
	 * @param request the current request
	 * @param deferredResult the DeferredResult for the current request
	 * @throws Exception in case of errors
	 */
	<T> void afterCompletion(NativeWebRequest request, DeferredResult<T> deferredResult) throws Exception;

}

自定义的DeferredResultProcessingInterceptor是通过<mvc:deferred-result-interceptors>配置的。

<mvc:annotation-driven>
    <mvc:async-support default-timeout="15000" task-executor="asyncTaskExecutor">
        <mvc:deferred-result-interceptors>
            <bean class="YourDeferredResultProcessingInterceptor"/>
        </mvc:deferred-result-interceptors>
    </mvc:async-support>
</mvc:annotation-driven>

当发起异步请求时,SpringMVC传统的HandlerInterceptor的postHandle()和afterCompletion()不会执行,但是等异步请求结束后它们还是会执行的。如果需要在异步处理完成之后做一些事情,也可以选择实现AsyncHandlerInterceptor接口的afterConcurrentHandlingStarted(),AsyncHandlerInterceptor接口继承了HandlerInterceptor。

(注:本文是基于Spring4.1.0所写)

0
0
分享到:
评论

相关推荐

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

    Spring MVC从3.2版本开始,引入了对异步请求的支持,这主要建立在Servlet 3.0及其以上版本的异步处理功能之上。下面将详细介绍如何在Spring MVC中配置和实现异步请求。 ### 1. 配置Web应用以支持异步处理 首先,你...

    servlet和springmvc源码servlet和springmvc源码

    Servlet3.0是Servlet规范的一个重要版本,引入了许多新特性,如异步处理、注解支持和简化部署描述符。 1. **Servlet3.0的新特性:** - **注解配置**:不再需要在web.xml中注册Servlet,可以直接在Servlet类上使用`...

    第三章 Spring MVC Servlet API与Json的支持

    3. 异步请求(如AJAX)中,通过`@ResponseBody`返回JSON数据,更新页面部分区域。 4. 实现RESTful API,使用HTTP动词(GET, POST, PUT, DELETE)和资源路径,配合JSON数据进行增删查改操作。 综上所述,Spring MVC...

    基于servlet3.0手写springmvc

    Servlet 3.0是Java Servlet API的一个重大更新,引入了许多新特性,如注解驱动的配置、异步Servlet处理、以及可插拔的部署描述符。这对于简化Web应用开发和提高其灵活性起到了关键作用。 Spring MVC 的核心是模型-...

    SpringMVC 异步 数据返回后台模型

    在处理前端与后端交互时,尤其是涉及到用户界面的动态更新,异步请求变得越来越重要。本篇文章将深入探讨SpringMVC如何支持异步数据返回,以及如何将这些数据以JSON格式传递给前端。 首先,让我们了解什么是异步...

    SpringMVC环境下实现的Ajax异步请求JSON格式数据

    在SpringMVC环境中实现Ajax异步请求JSON格式数据是一项常见的任务,这有助于创建更高效、交互性更强的Web应用程序。以下是一份详细的步骤指南和关键知识点解析: 首先,环境搭建是基础。确保你已经设置了标准的...

    springmvc处理异步请求的示例

    为了解决这个问题,Spring MVC 从3.2版本开始引入了对Servlet 3.0异步请求的支持。 异步请求的主要优点在于,它允许服务器在处理耗时操作时释放HTTP请求线程,让其他请求可以立即得到响应,从而提高系统吞吐量。在...

    SpringMVC配置

    3. **配置SpringMVC上下文**:在指定的初始化参数中(如servlet-context.xml),配置SpringMVC的行为,包括视图解析器、模型视图、拦截器、转换器和格式化器等。 ```xml xmlns:xsi=...

    springmvc + jquery + ajax + json 异步传递数据

    在前端,通过jQuery的$.ajax或者$.getJSON方法发起异步请求。这些方法允许我们指定URL、请求类型(GET或POST)、数据以及回调函数,以处理服务器返回的数据。JSON数据通常在回调函数中解析,然后可以更新DOM元素,...

    SpringMVC 4.0

    12. **Servlet 3.0支持**:SpringMVC 4.0充分利用Servlet 3.0的特性,如异步Servlet、WebSocket等,提高了Web应用的性能和功能。 13. **测试支持**:Spring MVC Test框架提供了对Spring MVC应用的单元测试和集成...

    spring mvc3.2.7+servlet3.1(jetty)+maven3+eclipse

    Servlet 3.1是Java Servlet规范的一个版本,它引入了许多新特性,比如异步处理能力,使得服务器可以在不阻塞线程的情况下处理请求,从而提高性能。Jetty是一个轻量级的开源Web服务器和Servlet容器,它可以很好地支持...

    SpringMvc笔记(第12次)1

    在本文中,我们将深入探讨Spring MVC中的异步请求处理,主要关注Servlet 3.0引入的异步处理机制以及Spring MVC如何利用这个特性。首先,理解同步和异步请求的区别至关重要。 8.1 同步处理是标准的HTTP请求响应模型...

    Spring注解驱动开发实战-springMVC

    对于springmvc-异步请求-返回Callable,Spring MVC提供了支持异步处理的能力。在Controller方法中,我们可以返回`Callable`对象,这使得请求可以在后台线程中处理,而主线程可以立即响应,提高系统的并发能力。例如...

    超级详细SpringMVC学习资料

    3. 数据绑定:支持自动将请求参数绑定到方法参数,如@RequestParam、@PathVariable等。 4. 视图解析:配置ViewResolver来决定如何生成视图,如JSP、Thymeleaf等。 三、SpringMVC流程 1. 用户发送HTTP请求到服务器。...

    SpringMVC.pdf

    在整个开发流程中,还需要特别注意请求参数的绑定和类型转换、请求中文乱码问题的处理、Session和Cookie的使用、Ajax异步请求的处理、文件上传功能的实现、异常处理机制以及拦截器的应用等细节。 对于文件上传,...

    springmvc 3.2.8 restful支持

    6. **Tomcat 8.0**:作为应用服务器,Tomcat 8.0对Servlet 3.0规范有良好的支持,这对于Spring MVC的应用部署和管理提供了便利,例如可以通过Web-INF/classes或Maven的war-exploded方式热部署应用。 7. **JSP视图...

    初识SpringMVC以及springmvc基本应用入门案例彩色PPT版本.pptx

    3. 在 pom.xml 文件中导入 SpringMVC 和 Servlet 相关依赖。 4. 定义处理请求的 Controller 类,并使用 @Controller 和 @RequestMapping 注解。 5. 配置 SpringMVC 的环境,如通过 @Configuration 和 @ComponentScan...

    SpringMVC示例

    - **异步处理**:支持异步请求处理,提高系统性能。 通过熟练掌握SpringMVC,开发者可以构建高效、灵活的Web应用程序。这个"SpringMVC示例"项目是一个很好的起点,帮助你了解和实践这些基本概念。通过逐步学习和...

    看透springMvc源代码分析与实践.pdf

    1. **SpringMVC基本架构**:SpringMVC框架基于Servlet API构建,通过DispatcherServlet作为前端控制器接收请求,然后根据配置的HandlerMapping将请求分发到相应的Controller。Controller处理业务逻辑后,通过...

Global site tag (gtag.js) - Google Analytics