關注我
,回復關鍵字「spring」,文章來源:https://c1n.cn/rrpG4
前言
Spring Event 同步使用
Spring Event 異步使用
實際業務開發過程中,業務邏輯可能非常複雜,核心業務 + N 個子業務。如果都放到一塊兒去做,代碼可能會很長,耦合度不斷攀升,維護起來也麻煩,甚至頭疼。還有一些業務場景不需要在一次請求中同步完成,比如郵件發送、短信發送等。
MQ 確實可以解決這個問題,但 MQ 重啊,非必要不提升架構複雜度。針對這些問題,我們了解一下 Spring Event。
Spring Event(Application Event)其實就是一個觀察者設計模式,一個 Bean 處理完成任務後希望通知其它 Bean 或者說一個 Bean 想觀察監聽另一個Bean 的行為。
Spring Event 用來解耦業務真的賊好用!
https://gitee.com/csps/mingyue-springboot-learning
| 自定義事件定義事件,繼承 ApplicationEvent 的類成為一個事件類:
importlombok.Data;importlombok.ToString;importorg.springframework.context.ApplicationEvent;/***@authorStrive*@date2022/4/2218:00*@description*/@Data@ToStringpublicclassOrderProductEventextendsApplicationEvent{/**該類型事件攜帶的信息*/privateStringorderId;publicOrderProductEvent(Objectsource,StringorderId){super(source);this.orderId=orderId;}}
| 定義監聽器監聽並處理事件,實現 ApplicationListener 接口或者使用@EventListener 註解:
importcom.csp.mingyue.event.events.OrderProductEvent;importlombok.SneakyThrows;importlombok.extern.slf4j.Slf4j;importorg.springframework.context.ApplicationListener;importorg.springframework.stereotype.Component;/***實現ApplicationListener接口,並指定監聽的事件類型**@authorStrive*@date2022/4/2409:09*@description*/@Slf4j@ComponentpublicclassOrderProductListenerimplementsApplicationListener<OrderProductEvent>{/**使用onApplicationEvent方法對消息進行接收處理*/@SneakyThrows@OverridepublicvoidonApplicationEvent(OrderProductEventevent){StringorderId=event.getOrderId();longstart=System.currentTimeMillis();Thread.sleep(2000);longend=System.currentTimeMillis();log.info("{}:校驗訂單商品價格耗時:({})毫秒",orderId,(end-start));}}
| 定義發布者發布事件,通過 ApplicationEventPublisher 發布事件:
importcom.csp.mingyue.event.events.OrderProductEvent;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.context.ApplicationContext;importorg.springframework.stereotype.Service;/***@authorStrive*@date2022/4/2409:25*@description*/@Slf4j@Service@RequiredArgsConstructorpublicclassOrderService{/**注入ApplicationContext用來發布事件*/privatefinalApplicationContextapplicationContext;/***下單**@paramorderId訂單ID*/publicStringbuyOrder(StringorderId){longstart=System.currentTimeMillis();//1.查詢訂單詳情//2.檢驗訂單價格(同步處理)applicationContext.publishEvent(newOrderProductEvent(this,orderId));//3.短信通知(異步處理)longend=System.currentTimeMillis();log.info("任務全部完成,總耗時:({})毫秒",end-start);return"購買成功";}}
| 單測執行importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;/***@authorStrive*@date2022/4/2409:28*@description*/@SpringBootTestpublicclassOrderServiceTest{@AutowiredprivateOrderServiceorderService;@TestpublicvoidbuyOrderTest(){orderService.buyOrder("732171109");}}
執行結果如下:
2022-04-2410:13:17.535INFO44272---[main]c.c.m.e.listener.OrderProductListener: 732171109:校驗訂單商品價格耗時:(2008)毫秒2022-04-2410:13:17.536INFO44272---[main]c.c.mingyue.event.service.OrderService:任務全部完成,總耗時:(2009)毫秒
有些業務場景不需要在一次請求中同步完成,比如郵件發送、短信發送等。
| 自定義事件importlombok.AllArgsConstructor;importlombok.Data;/***@authorStrive*@date2022/4/2410:18*@description*/@Data@AllArgsConstructorpublicclassMsgEvent{/**該類型事件攜帶的信息*/publicStringorderId;}
| 定義監聽器推薦使用@EventListener 註解:
importcom.csp.mingyue.event.events.MsgEvent;importlombok.SneakyThrows;importlombok.extern.slf4j.Slf4j;importorg.springframework.context.event.EventListener;importorg.springframework.stereotype.Component;/***@authorStrive*@date2022/4/2410:20*@description*/@Slf4j@ComponentpublicclassMsgListener{@SneakyThrows@EventListener(MsgEvent.class)publicvoidsendMsg(MsgEventevent){StringorderId=event.getOrderId();longstart=System.currentTimeMillis();log.info("開發發送短信");log.info("開發發送郵件");Thread.sleep(4000);longend=System.currentTimeMillis();log.info("{}:發送短信、郵件耗時:({})毫秒",orderId,(end-start));}}
| 定義發布者/***下單**@paramorderId訂單ID*/publicStringbuyOrder(StringorderId){longstart=System.currentTimeMillis();//1.查詢訂單詳情//2.檢驗訂單價格(同步處理)applicationContext.publishEvent(newOrderProductEvent(this,orderId));//3.短信通知(異步處理)applicationContext.publishEvent(newMsgEvent(orderId));longend=System.currentTimeMillis();log.info("任務全部完成,總耗時:({})毫秒",end-start);return"購買成功";}
| 單測執行(同步)@TestpublicvoidbuyOrderTest(){orderService.buyOrder("732171109");}
執行結果如下:
2022-04-2410:24:13.905INFO54848---[main]c.c.m.e.listener.OrderProductListener: 732171109:校驗訂單商品價格耗時:(2004)毫秒2022-04-2410:24:13.906INFO54848---[main]c.c.mingyue.event.listener.MsgListener:開發發送短信2022-04-2410:24:13.907INFO54848---[main]c.c.mingyue.event.listener.MsgListener:開發發送郵件2022-04-2410:24:17.908INFO54848---[main]c.c.mingyue.event.listener.MsgListener: 732171109:發送短信、郵件耗時:(4002)毫秒2022-04-2410:24:17.908INFO54848---[main]c.c.mingyue.event.service.OrderService:任務全部完成,總耗時:(6008)毫秒
| 開啟異步啟動類增加@EnableAsync 註解:
@EnableAsync@SpringBootApplicationpublicclassMingYueSpringbootEventApplication{publicstaticvoidmain(String[]args){SpringApplication.run(MingYueSpringbootEventApplication.class,args);}}
Listener 類需要開啟異步的方法增加@Async 註解:
@Async@SneakyThrows@EventListener(MsgEvent.class)publicvoidsendMsg(MsgEventevent){StringorderId=event.getOrderId();longstart=System.currentTimeMillis();log.info("開發發送短信");log.info("開發發送郵件");Thread.sleep(4000);longend=System.currentTimeMillis();log.info("{}:發送短信、郵件耗時:({})毫秒",orderId,(end-start));}
| 單測執行(異步)發送短信的線程顯示 task-1,主線程結束後(總耗時:(2017)毫秒)控制台停止打印了:2022-04-2410:30:59.002INFO59448---[main]c.c.m.e.listener.OrderProductListener: 732171109:校驗訂單商品價格耗時:(2009)毫秒2022-04-2410:30:59.009INFO59448---[main]c.c.mingyue.event.service.OrderService:任務全部完成,總耗時:(2017)毫秒2022-04-2410:30:59.028INFO59448---[task-1]c.c.mingyue.event.listener.MsgListener:開發發送短信2022-04-2410:30:59.028INFO59448---[task-1]c.c.mingyue.event.listener.MsgListener:開發發送郵件
如果後端API一次返回10萬條數據,前端應該如何處理?VS Code 7 月更新:Spring 支持再增強,Lombok 支持重大提升!IntelliJ IDEA 2022.2 發布首個Beta版本不用 Spring 居然連最基本的接口都不會寫了!
關注後端面試那些事,回復【2022面經】
獲取最新大廠Java面經
最後重要提示:高質量的技術交流群,限時免費開放,今年抱團最重要。想進群的,關注SpringForAll社區
,回復關鍵詞:加群,拉你進群。