場景描述
在秒殺微服務(wù)中赡勘,筆者在需要各種校驗前端傳來的參數(shù)后瞎暑,通過 Redis 加鎖限流(切面A)并返回妙蔗,最后封裝訂單數(shù)據(jù)推送到 RabbitMQ 消息隊列(切面B)做善后工作蝇摸。
問題:如何將 切面 A 的數(shù)據(jù)傳遞 給切面B呢壤圃?
/**
* 添加到秒殺流程
*
* @param killId 秒殺商品緩存鍵 sessionId_skuId
* @param key 隨機碼 randomCode
* @param num 數(shù)量
* @return {@link R}
*/
@GetMapping("/kill")
public R addToSeckill(
@RequestParam("killId") String killId,
@RequestParam("key") String key,
@RequestParam("num") Integer num) {
// 實現(xiàn)類只是帶有兩個注解方法夹孔,返回 null(因為全部交給切面托管了)
String orderSn = seckillService.kill(killId, key, num);
if (StringUtils.isEmpty(orderSn)) {
return R.error();
}
return R.ok().setData(orderSn);
}
解決方案
通過參數(shù)傳遞數(shù)據(jù)被盈,通過捕獲異常保證業(yè)務(wù)邏輯(離譜但有用) ??
// 強制修改參數(shù),通過異常返回正常流程搭伤,而通過AOP消息隊列處理收尾動作
try {
return pjp.proceed(new Object[]{orderTo, null, null});
} catch (Throwable e) {
return orderSn;
}
注意事項:
參數(shù)一致性:必須偽造和方法簽名的數(shù)量相等的參數(shù) ? 否則線程會拋出異常 I 就返回了只怎,無法執(zhí)行
pjp.proceed
原始方法 ? 無法執(zhí)行第二個切面
java.lang.IllegalArgumentException: Expecting 3 arguments to proceed, but was passed 1 arguments
捕獲異常不拋出,直接執(zhí)行正常業(yè)務(wù)邏輯 ? 否則線程將吞沒異常 II
cn.miozus.gulimall.common.to.mq.SeckillOrderTo cannot be cast to java.lang.String
3.雖然兩個切面都返回了 orderSn
怜俐,實際最終只有切面A傳遞到了控制層和前端身堡, 切面B的返回值成了擺設(shè)。
打斷點查看兩個切面的跳轉(zhuǎn)過程拍鲤。
切面A:準備跳轉(zhuǎn)第二個切面.png
切面B:發(fā)送消息完成.png
打印日志盾沫,可見場景需求裁赠,已經(jīng)滿足了。
2022-03-29 17:32:56.521 INFO 7904 --- [io-25000-exec-8] c.m.g.s.aspect.SeckillRabbitMqAspect : 快速創(chuàng)建訂單:發(fā)送消息創(chuàng)建完成: 202203291732444881508738921192005634
2022-03-29 17:33:01.526 INFO 7904 --- [io-25000-exec-8] c.m.g.s.controller.SeckillController : 秒殺創(chuàng)建訂單用時:28778
?? seckill orderSn = 202203291732444881508738921192005634
2022-03-29 17:33:01.527 INFO 7904 --- [nectionFactory5] c.m.g.s.config.RabbitMqSeckillConfig : ?? 消息已發(fā)送, params: correlationData:null,ack:true,cause:null
其他方案
最簡單的辦法赴精,不切了佩捞,兩個切面耦合在一起。注入和調(diào)用方法蕾哟。