標籤:
從spring3.2開始,支援servlet3的非同步請求,這對於處理耗時的請求如緩慢的資料庫查詢是非常有好處的,不至於很快的耗光servlet的線程池,影響可擴充性。
讓我們先來瞭解一下servlet是怎麼處理非同步作業的:
- 通過調用request.startAsync(),ServletRequest就變成非同步模式。主要的影響是Servlet、Filter會退出,但是Response保持開啟用來完成請求處理。
- 調用request.startAsync()返回AsyncContext執行個體,可進一步控制非同步處理。例如,它提供dispatch方法,可以從應用線程調用以分發請求回Servlet容器。非同步調度和forward的方式是相似的,但是非同步調度是由應用線程到Servlet容器線程產生的,而forward的方式是同時發生在相同的Servlet容器線程。
- ServletRequest提供當前的DispatcherType,它可以用來在非同步調度中區分正在處理的初始請求線程是Servlet還是Filter。
接著來看一下callable是怎麼處理非同步作業的:
- Controller返回一個Callable執行個體;
- Spring MVC開始非同步處理並在一個單獨的線程中,提交Callable執行個體給TaskExecutor處理;
- DispatcherServlet和所有的Filter退出請求線程但是response儲存開啟;
- Callable返回結果,Spring MVC分發請求回Servlet容器;
- DispatcherServlet重新調用並繼續處理從Callable執行個體中非同步返回的結果。
現在來看一下代碼是怎麼實現的
1、pom.xml
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version></dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>3.2.13.RELEASE</version></dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>3.2.13.RELEASE</version></dependency>
2、applicationContext-mvc.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <context:component-scan base-package="com.test"/> <mvc:annotation-driven> <!-- 配置逾時時間 --> <mvc:async-support default-timeout="3000"> <!-- 這裡可以配置callable或者deferred-result攔截器 --> </mvc:async-support> </mvc:annotation-driven></beans>
3、web.xml , 當有 很多 filter 時,filter 也一定要添加非同步支援
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <async-supported>true</async-supported> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping></web-app>
web.xml需要聲明web-app_3_0.xsd和version=”3.0″,啟用非同步支援<async-supported>true</async-supported>
4、CallableController.java
package com.test.controller; import org.springframework.stereotype.Controller;import org.springframework.ui.ModelMap;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.servlet.ModelAndView; import java.util.concurrent.Callable; /** * spring實現方式: * 1、把任務提交給Executor非同步執行 */@Controllerpublic class CallableController { @RequestMapping(value = "/callable1", method = RequestMethod.GET) public Callable<String> callable1(final ModelMap modelMap) { return new Callable<String>() { public String call() throws Exception { Thread.sleep(2 * 1000L); //暫停2秒return "hello callable"; } }; } }
5,tomcat 部分,如果 tomcat 部署有 session 分頁式快取區外掛程式,則在外掛程式配置的地方,也要添加非同步支援:
<!-- redis 緩衝支援 -->
<Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve" asyncSupported="true" /> <Manager className="com.radiadesign.catalina.session.RedisSessionManager" host="localhost" port="6379" database="0" maxInactiveInterval="60" />
6, 啟動服務,測試:
http://localhost:8088/test/callable1
7, rsp:
hello callable
Spring MVC 非同步測試