1. 程式人生 > >spring mvc對非同步請求的處理

spring mvc對非同步請求的處理

在spring mvc3.2及以上版本增加了對請求的非同步處理,是在servlet3的基礎上進行封裝的。

1、修改web.xml

複製程式碼
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 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"
> ... </web-app>
複製程式碼

1.1、宣告version="3.0",宣告web-app_3_0.xsd

1.2、為servlet或者filter設定啟用非同步支援:<async-supported>true</async-supported>,修改WEB應用的web.xml

複製程式碼
<!-- spring mvc -->
<servlet>
<servlet-name>SpringMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</
servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>...</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet>
複製程式碼

2、使controller類支援async

2.1、返回java.util.concurrent.Callable來完成非同步處理

複製程式碼
package org.springframework.samples.mvc.async;
  
import java.util.concurrent.Callable;
  
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.WebAsyncTask;
  
@Controller
@RequestMapping("/async/callable")
public class CallableController {
    @RequestMapping("/response-body")
    public @ResponseBody Callable<String> callable() {
  
        return new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                return "Callable result";
            }
        };
    }
  
    @RequestMapping("/view")
    public Callable<String> callableWithView(final Model model) {
  
        return new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                model.addAttribute("foo", "bar");
                model.addAttribute("fruit", "apple");
                return "views/html";
            }
        };
    }
  
    @RequestMapping("/exception")
    public @ResponseBody Callable<String> callableWithException(
            final @RequestParam(required=false, defaultValue="true") boolean handled) {
  
        return new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                if (handled) {
                    // see handleException method further below
                    throw new IllegalStateException("Callable error");
                }
                else {
                    throw new IllegalArgumentException("Callable error");
                }
            }
        };
    }
  
    @RequestMapping("/custom-timeout-handling")
    public @ResponseBody WebAsyncTask<String> callableWithCustomTimeoutHandling() {
  
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                return "Callable result";
            }
        };
  
        return new WebAsyncTask<String>(1000, callable);
    }
  
    @ExceptionHandler
    @ResponseBody
    public String handleException(IllegalStateException ex) {
        return "Handled exception: " + ex.getMessage();
    }
  
}
複製程式碼

2.2、在非同步處理完成時返回org.springframework.web.context.request.async.DeferredResult其他執行緒,例如一個JMS或一個AMQP訊息,Redis通知等等:

複製程式碼
@RequestMapping("/quotes")
@ResponseBody
public DeferredResult<String> quotes() {
  DeferredResult<String> deferredResult = new DeferredResult<String>();
  // Add deferredResult to a Queue or a Map...
  return deferredResult;
}
    
// In some other thread...
deferredResult.setResult(data);
// Remove deferredResult from the Queue or Map
複製程式碼

3、spring配置檔案的修改

spring mvc的dtd的宣告必須大於等於3.2

<mvc:annotation-driven>
<!--  可不設定,使用預設的超時時間 -->
    <mvc:async-support default-timeout="3000"/>
</mvc:annotation-driven>

 實際使用示例:

function deferred(){
    $.get('quotes.htm',function(data){
        console.log(data);
        deferred();//每次請求完成,再發一次請求,避免客戶端定時重新整理來獲取資料
    });
}

這麼做的好處避免web server的連線池被長期佔用而引起效能問題,呼叫後生成一個非web的服務執行緒來處理,增加web伺服器的吞吐量~~