摘要:本篇博文是“Java秒杀系统实战系列文章”的第十八篇,我们将继续秒杀系统的优化之路。在本篇文章中我们将基于RabbitMQ异步通信、FIFO(先进先出)、接口限流的特性,在执行秒杀核心的处理逻辑之前架上一层“限流”的处理逻辑,从而让瞬时产生的,犹如波涛汹涌、潮水般的请求流量变得井井有条、有序性地到达后端的秒杀接口!
内容:接着上一篇章的讲解,我们需要在后端 接收前端高并发产生多线程请求时,及时高效地转移巨大的用户请求之MQ中间件中,为后端秒杀接口赢得足够的、规范化的处理!在这一过程,前端和后端的交互是异步的,因此,在前后端处理逻辑层面跟前面篇章的处理方式将有所不同。
(1)首先,在Controller层,需要提供响应前端秒杀请求的方法,该方法不直接处理秒杀的核心业务逻辑,而是将其转移至MQ中间件中,并立即返回success的状态信息给回到前端,其代码如下所示:
@Autowired
private RabbitSenderService rabbitSenderService;
//商品秒杀核心业务逻辑-mq限流
@RequestMapping(value = prefix+"/execute/mq",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public BaseResponse executeMq(@RequestBody @Validated KillDto dto, BindingResult result, HttpSession session){
if (result.hasErrors() || dto.getKillId()<=0){
return new BaseResponse(StatusCode.InvalidParams);
}
Object uId=session.getAttribute("uid");
if (uId==null){
return new BaseResponse(StatusCode.UserNotLogin);
}
Integer userId= (Integer)uId ;
BaseResponse response=new BaseResponse(StatusCode.Success);
Map<String,Object> dataMap= Maps.newHashMap();
try {
dataMap.put("killId",dto.getKillId());
dataMap.put("userId",userId);
response.setData(dataMap);
dto.setUserId(userId);
rabbitSenderService.sendKillExecuteMqMsg(dto);
}catch (Exception e){
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
(2)前端info.jsp再提交秒杀请求并接收到后端的返回信息后,便立即跳转至相应的页面,即秒杀结果查看页(准备查看相应的秒杀结果的),该页面是通过响应后端Controller器方法进行跳转的,其页面的js代码如下所示:
function executeKillMq() {
$.ajax({
type: "POST",
url: "${ctx}/kill/execute/mq",
contentType: "application/json;charset=utf-8",
data: JSON.stringify(getJsonData()),
dataType: "json",
success: function(res){
if (res.code==0) {
//立即跳转至“秒杀结果查看页”
window.location.href="${ctx}/kill/execute/mq/to/result?killId="+$("#killId").val()
}else{
window.location.href="${ctx}/kill/execute/fail"
}
},
error: function (message) {
alert("提交数据失败!");
return;
}
});
}