springMVC中也整合了异步请求的特性,我们只需要配置好支持异步请求特性,然后结合java自带的回调函数处理就可以实现简单的异步请求,但是这样的异步请求往往是不能满足我们需求的,所以最终我们还是会使用比较完整的异步请求接口,那就是spring的WebAsyncTask和DeferredResult。
首先需要添加配置项:
springmvc-servlet.xml:
<mvc:annotation-driven>
<mvc:async-support default-timeout="5000"/>
</mvc:annotation-driven>
web.xml的所有servlet和filter
<async-supported>true</async-supported>
- 使用Callable实现异步请求
@RequestMapping("/response-body")
public @ResponseBody Callable<String> callable() {
Callable<String> asyncTask = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(4000);
return "Callableresult";
}
};
System.out.println("已交给服务线程处理");
return asyncTask;
}
这种方法可以实现异步请求,但是没有设置超时时间和相关超时回调。只是客户端发起请求,服务端保证执行完成即可,然后将直接成功的结果返回给客户端,客户端根绝返回值判断是否需要发起另一个请求。
- 使用WebAsyncTask实现异步请求
@RequestMapping("/response-body2")
public @ResponseBody WebAsyncTask<String> webAsyncHandle() {
Callable<String> asyncTask = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(10000);
return "Callableresult";//超时之后不会执行返回操作,但是return之前的能够执行完成
}
};
System.out.println("已交给服务线程处理");
WebAsyncTask<String> webAsyncTask = new WebAsyncTask<String>(5000, asyncTask);
webAsyncTask.onCompletion(new CompleteWork(webAsyncTask));
webAsyncTask.onTimeout(timeOutCallBack());
System.out.println("main over");
return webAsyncTask;
}
public Callable<String> timeOutCallBack(){
Callable<String> callback = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("我超时了");
return "我超时了";
}
};
return callback;
}
//内部类
class CompleteWork<T> implements Runnable{
private T t;
public CompleteWork(T t){
this.t = t;
}
@Override
public void run() {
if (t instanceof WebAsyncTask) {
if (((WebAsyncTask) t).getTimeout() > 0) {//没啥用,超时之后返回值也是大于0
System.out.println("WebAsyncTask:我执行完啦!");
}
}else if (t instanceof DeferredResult) {
if(!((DeferredResult) t).isSetOrExpired()){
System.out.println("DeferredResult:我执行完啦!");
}
}
}
}
这种方法通过使用spring的WebAsyncTask实现了异步请求,并且可以设置超时时间,以及超时和完成之后的回调函数。需要注意的是,超时之后也会回调onCompletion中设置方法。
- 使用DeferredResult实现异步请求
@RequestMapping("/response-body3")
@ResponseBody
public DeferredResult<String> quotes(HttpServletResponse response) {
DeferredResult<String> deferredResult = new DeferredResult<String>(5000);
dealInOtherThread(deferredResult);
return deferredResult;
}
public void dealInOtherThread(DeferredResult<String> deferredResult){
deferredResult.onTimeout(new TimeOutWork());
deferredResult.onCompletion(new CompleteWork(deferredResult));
new Thread(new work(deferredResult)).start();
System.out.println("main over");
}
//内部类
class TimeOutWork implements Runnable{
private DeferredResult<String> deferredResult;
public TimeOutWork(DeferredResult<String> deferredResult){
this.deferredResult = deferredResult;
}
@Override
public void run() {
System.out.println("我超时啦!");
deferredResult.setErrorResult("我超时了");
}
}
这种方法跟上面的WebAsyncTask类似,超时之后也会调用onCompletion函数。所以我们需要在回调函数中增加超时的判断。上面的方法中DeferredResult可以通过isSetOrExpired()来判断,但是WebAsyncTask还不知道如何判断。还有一点就是DeferredResult是在设置deferredResult.setResult(…)的时候就响应客户端,而WebAsyncTask是直接return。