官方文档对Callable、DeferredResult 的解释
DeferredResult and Callable return values in controller methods and provide basic support for a single asynchronous return value
大致意思是说:在控制器中,可以用Callable或DeferredResult 为异步方法提供一个返回值。
简单来说就是一个请求进来,如果你使用了DeferredResult或者Callable,在没有得到返回数据之前,DispatcherServlet和所有Filter就会退出Servlet容器线程,但响应保持打开状态,一旦返回数据有了,这个DispatcherServlet就会被再次调用并且处理,以异步产生的方式,向请求端返回值。
这么做的好处就是请求不会长时间占用服务连接池,提高服务器的吞吐量。
使用Callable异步处理Rest服务
通过Callable来进行异步处理时,副线程是通过主线程来调用的,处理相对简单。
代码如下
@RequestMapping("/order2")
public Callable<String> order2(){
logger.info("主线程开始");
Callable<String> result = new Callable<String>() {
@Override
public String call() throws Exception {
logger.info("副线程开始");
Thread.sleep(1000);
logger.info("副线程返回");
return "success";
}
};
logger.info("主线程返回");
return result;
}
日志输出
2020-04-11 14:11:02.185 INFO 1768 --- [nio-8080-exec-2] com.imooc.web.async.AsyncController : 主线程开始
2020-04-11 14:11:02.186 INFO 1768 --- [nio-8080-exec-2] com.imooc.web.async.AsyncController : 主线程返回
2020-04-11 14:11:02.201 INFO 1768 --- [ MvcAsync1] com.imooc.web.async.AsyncController : 副线程开始
2020-04-11 14:11:03.201 INFO 1768 --- [ MvcAsync1] com.imooc.web.async.AsyncController : 副线程返回
可以看到,主线程在完成调用后便继续执行其它的任务。
使用DeferredResult异步处理Rest服务
一旦启用了异步请求处理功能 ,控制器就可以将返回值包装在DeferredResult,控制器可以从不同的线程异步产生返回值。优点就是可以实现两个完全不相干的线程间的通信。
@RestController
public class AsyncController {
@Autowired
private MockQueue mockQueue;
@Autowired
private DeferredResultHolder deferredResultHolder;
private Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping("/order")
public DeferredResult<String> order() throws Exception {
logger.info("主线程开始");
String orderNumber = RandomStringUtils.randomNumeric(8);
mockQueue.setPlaceOrder(orderNumber);
DeferredResult<String> result = new DeferredResult<>();
deferredResultHolder.getMap().put(orderNumber, result);
logger.info("主线程返回");
return result;
}
}
模拟消息队列
@Component
public class MockQueue {
private String placeOrder;
private String completeOrder;
private Logger logger = LoggerFactory.getLogger(getClass());
public String getPlaceOrder() {
return placeOrder;
}
public void setPlaceOrder(String placeOrder) throws Exception {
new Thread(() -> {
logger.info("接到下单请求, " + placeOrder);
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
this.completeOrder = placeOrder;
logger.info("下单请求处理完毕," + placeOrder);
}).start();
}
public String getCompleteOrder() {
return completeOrder;
}
public void setCompleteOrder(String completeOrder) {
this.completeOrder = completeOrder;
}
}
封装DeferredResult
@Component
public class DeferredResultHolder {
private Map<String, DeferredResult<String>> map = new HashMap<String, DeferredResult<String>>();
public Map<String, DeferredResult<String>> getMap() {
return map;
}
public void setMap(Map<String, DeferredResult<String>> map) {
this.map = map;
}
}
监听器
@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
private MockQueue mockQueue;
@Autowired
private DeferredResultHolder deferredResultHolder;
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
new Thread(() -> {
while (true) {
if (StringUtils.isNotBlank(mockQueue.getCompleteOrder())) {
String orderNumber = mockQueue.getCompleteOrder();
logger.info("返回订单处理结果:"+orderNumber);
deferredResultHolder.getMap().get(orderNumber).setResult("place order success");
mockQueue.setCompleteOrder(null);
}else{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
日志输出
2020-04-11 14:14:20.522 INFO 1768 --- [nio-8080-exec-6] com.imooc.web.async.AsyncController : 主线程开始
2020-04-11 14:14:20.525 INFO 1768 --- [nio-8080-exec-6] com.imooc.web.async.AsyncController : 主线程返回
2020-04-11 14:14:20.526 INFO 1768 --- [ Thread-65] com.imooc.web.async.MockQueue : 接到下单请求, 55018371
2020-04-11 14:14:21.526 INFO 1768 --- [ Thread-65] com.imooc.web.async.MockQueue : 下单请求处理完毕,55018371
2020-04-11 14:14:21.619 INFO 1768 --- [ Thread-51] com.imooc.web.async.QueueListener : 返回订单处理结果:55018371
参考文案:https://blog.csdn.net/smollsnail/article/details/79164826