同步请求图示:
同步处理的图示如上:HTTP请求,tomcat或其他中间件会有一个相应的线程来处理这个Http请求,所有的业务逻辑都会在这个线程里去执行,最后返回Http响应。但是tomcat等中间件,它们可以管理的线程数是有限的,当数量达到一定程度之后,再有请求进入,会被阻塞掉。
简单异步图示:
异步处理过程:当一个http请求进入后,tomcat等中间件的主线程调用副线程来执行业务逻辑,当副线程处理完成后,主线程再返回结果,在副线程处理整个业务逻辑的中,主线程会空闲出来去出来其他请求,也就是说采用上述这种模式处理http请求,服务器的吞吐量会有有明显的提升。使用异步返回,需使在web.xml将version配置为3.0版本的。
在servlet及所有的filter中配置异步支持。
简单实现如下:
更为复杂的业务场景的异步返回如下所示:
Htpp请求通过线程一处理,并将消息发送到消息队列,应用2处于不同的服务器,其接收到消息并将消息返回,线程2监听到处理结果,将消息返回,线程一及线程二不知道对方的存在。这种业务情况,单开一个线程是无法解决的,需要使用DeferredResult类。
简单的实现代码如下:
controller层:@Controller
@RequestMapping("/test/")
@Slf4j
public class TestController {
@Autowired
private MockQueue mockQueue;
@Autowired
private DeferredResultHolder deferredResultHolder;
@RequestMapping("order")
@ResponseBody
public DeferredResult<String> test() throws InterruptedException {
log.info("主线程开始");
String orderNo = RandomUtils.nextInt() + "";
mockQueue.setPlaceOrder(orderNo);
DeferredResult<String> result = new DeferredResult<String>();
deferredResultHolder.getMap().put(orderNo, result);
log.info("主线程结束");
return result;
}
}
伪消息队列类:
@Slf4j
@Component
public class MockQueue {
private String placeOrder;
private String compeleteOrder;
public String getPlaceOrder() {
return placeOrder;
}
public void setPlaceOrder(String placeOrder) throws InterruptedException {
new Thread(()->{ log.info("收到下单的请求");
this.placeOrder = placeOrder;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.compeleteOrder = placeOrder;
log.info("完成下单的请求");}).start();
}
public String getCompeleteOrder() {
return compeleteOrder;
}
public void setCompeleteOrder(String compeleteOrder) {
this.compeleteOrder = compeleteOrder;
}
}
伪队列监听类:
@Slf4j
@Component
public class QueueListener implements ApplicationListener{
@Autowired
private MockQueue mockQueue;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
new Thread(() ->{
while (true){
if(StringUtils.isNotBlank(mockQueue.getCompeleteOrder())){
String orderNum = mockQueue.getCompeleteOrder();
log.info("返回订单处理结果" + orderNum);
deferredResultHolder.getMap().get(orderNum).setResult("success");
mockQueue.setCompeleteOrder(null);
}else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
容器类:
@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;
}
}