Spring Event觀察者模式事件監(jiān)聽(tīng)詳解
Spring Event事件監(jiān)聽(tīng)
Spring Event(Application Event)其實(shí)就是一個(gè)觀察者設(shè)計(jì)模式,一個(gè) Bean 處理完成任務(wù)后希望通知其它 Bean 或者說(shuō)一個(gè) Bean 想觀察監(jiān)聽(tīng)另一個(gè)Bean 的行為。在開(kāi)發(fā)中我們經(jīng)常就會(huì)遇到修改一個(gè)bean時(shí),同時(shí)需要去修改其他得bean?;蛘哒f(shuō)當(dāng)一個(gè)bean得值發(fā)生變化時(shí),需要修改另一個(gè)bean得業(yè)務(wù)。還有一些業(yè)務(wù)場(chǎng)景不需要在一次請(qǐng)求中同步完成,比如郵件發(fā)送、短信發(fā)送等。
MQ 確實(shí)可以解決這個(gè)問(wèn)題,但 MQ比較重,非必要不提升架構(gòu)復(fù)雜度。因此Spring Event是非常好得選擇。
依賴:引入Spring得核心依賴即可
Spring Event同步使用
自定義事件
定義事件,繼承 ApplicationEvent 的類成為一個(gè)事件類:
@Data public class OrderProductEvent extends ApplicationEvent { /** 該類型事件攜帶的信息 */ private String orderId; public OrderProductEvent(Object source, String orderId) { super(source); this.orderId = orderId; } }
定義監(jiān)聽(tīng)器
監(jiān)聽(tīng)并處理事件,實(shí)現(xiàn) ApplicationListener 接口或者使用 @EventListener 注解:
/** * 實(shí)現(xiàn) ApplicationListener 接口,并指定監(jiān)聽(tīng)的事件類型 */ @Slf4j @Component public class OrderProductListener implements ApplicationListener<OrderProductEvent> { /** * 使用 onApplicationEvent 方法對(duì)消息進(jìn)行接收處理 * * */ @SneakyThrows @Override public void onApplicationEvent(OrderProductEvent event) { String orderId = event.getOrderId(); long start = System.currentTimeMillis(); Thread.sleep(2000); long end = System.currentTimeMillis(); log.info("{}:校驗(yàn)訂單商品價(jià)格耗時(shí):({})毫秒", orderId, (end - start)); } }
定義發(fā)布者
發(fā)布事件,通過(guò) ApplicationEventPublisher 發(fā)布事件:
@Slf4j @Service @RequiredArgsConstructor public class OrderService { /** 注入ApplicationContext用來(lái)發(fā)布事件 */ private final ApplicationContext applicationContext; /** * 下單 * * @param orderId 訂單ID */ public String buyOrder(String orderId) { long start = System.currentTimeMillis(); // 1.查詢訂單詳情 // 2.檢驗(yàn)訂單價(jià)格 (同步處理) applicationContext.publishEvent(new OrderProductEvent(this, orderId)); long end = System.currentTimeMillis(); log.info("任務(wù)全部完成,總耗時(shí):({})毫秒", end - start); return "購(gòu)買(mǎi)成功"; } }
測(cè)試執(zhí)行
@SpringBootTest public class OrderServiceTest { @Autowired private OrderService orderService; @Test public void buyOrderTest() { orderService.buyOrder("732171109"); } }
c.l.l.event.OrderProductListener : 732171109:校驗(yàn)訂單商品價(jià)格耗時(shí):(2001)毫秒
c.llp.llpspringretry.event.OrderService : 任務(wù)全部完成,總耗時(shí):(2005)毫秒
Debug執(zhí)行流程
Spring Event 異步使用
有些業(yè)務(wù)場(chǎng)景不需要在一次請(qǐng)求中同步完成,比如郵件發(fā)送、短信發(fā)送等。
自定義事件
import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class MsgEvent { /** 該類型事件攜帶的信息 */ public String orderId; }
定義監(jiān)聽(tīng)器
推薦使用 @EventListener 注解:
@Slf4j @Component public class MsgListener { @Async @SneakyThrows @EventListener(MsgEvent.class) public void sendMsg(MsgEvent event) { String orderId = event.getOrderId(); long start = System.currentTimeMillis(); log.info("開(kāi)發(fā)發(fā)送短信"); log.info("開(kāi)發(fā)發(fā)送郵件"); Thread.sleep(4000); long end = System.currentTimeMillis(); log.info("{}:發(fā)送短信、郵件耗時(shí):({})毫秒", orderId, (end - start)); } }
定義發(fā)布者
@Slf4j @Service @RequiredArgsConstructor public class OrderService { /** 注入ApplicationContext用來(lái)發(fā)布事件 */ private final ApplicationContext applicationContext; /** * 下單 * * @param orderId 訂單ID */ public String buyOrder(String orderId) { long start = System.currentTimeMillis(); // 1.查詢訂單詳情 // 2.檢驗(yàn)訂單價(jià)格 (同步處理) // applicationContext.publishEvent(new OrderProductEvent(this, orderId)); // 3.短信通知(異步處理) 新開(kāi)線程執(zhí)行監(jiān)聽(tīng)得業(yè)務(wù) applicationContext.publishEvent(new MsgEvent(orderId)); long end = System.currentTimeMillis(); log.info("任務(wù)全部完成,總耗時(shí):({})毫秒", end - start); return "購(gòu)買(mǎi)成功"; } }
開(kāi)啟異步支持
@EnableAsync開(kāi)啟異步支持
@EnableAsync @EnableRetry @SpringBootApplication public class LlpSpringRetryApplication { public static void main(String[] args) { SpringApplication.run(LlpSpringRetryApplication.class, args); } }
c.llp.llpspringretry.event.OrderService : 任務(wù)全部完成,總耗時(shí):(6)毫秒
c.llp.llpspringretry.event.MsgListener : 開(kāi)發(fā)發(fā)送短信
c.llp.llpspringretry.event.MsgListener : 開(kāi)發(fā)發(fā)送郵件
到此這篇關(guān)于Spring Event觀察者模式事件監(jiān)聽(tīng)詳解的文章就介紹到這了,更多相關(guān)Spring Event事件監(jiān)聽(tīng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中的阻塞隊(duì)列BlockingQueue使用詳解
這篇文章主要介紹了Java中的阻塞隊(duì)列BlockingQueue使用詳解,阻塞隊(duì)列是一種線程安全的數(shù)據(jù)結(jié)構(gòu),用于在多線程環(huán)境下進(jìn)行數(shù)據(jù)交換,它提供了一種阻塞的機(jī)制,當(dāng)隊(duì)列為空時(shí),消費(fèi)者線程將被阻塞,直到隊(duì)列中有數(shù)據(jù)可供消費(fèi),需要的朋友可以參考下2023-10-10SpringBoot + minio實(shí)現(xiàn)分片上傳、秒傳、續(xù)傳功能
MinIO是一個(gè)基于Go實(shí)現(xiàn)的高性能、兼容S3協(xié)議的對(duì)象存儲(chǔ),使用MinIO構(gòu)建用于機(jī)器學(xué)習(xí),分析和應(yīng)用程序數(shù)據(jù)工作負(fù)載的高性能基礎(chǔ)架構(gòu),這篇文章主要介紹了SpringBoot + minio實(shí)現(xiàn)分片上傳、秒傳、續(xù)傳,需要的朋友可以參考下2023-06-06java substring(a)與substring(a,b)的使用說(shuō)明
這篇文章主要介紹了java substring(a)與substring(a,b)的使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10java實(shí)現(xiàn)網(wǎng)站微信掃碼支付
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)網(wǎng)站微信掃碼支付,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07java程序運(yùn)行時(shí)內(nèi)存分配詳解
這篇文章主要介紹了java程序運(yùn)行時(shí)內(nèi)存分配詳解 ,需要的朋友可以參考下2016-07-07Python基礎(chǔ)之如何使用multiprocessing模塊
今天帶大家學(xué)習(xí)python多進(jìn)程的相關(guān)知識(shí),文中對(duì)multiprocessing模塊的使用作了非常詳細(xì)的介紹,需要的朋友可以參考下2021-06-06MyBatis映射文件中的動(dòng)態(tài)SQL實(shí)例詳解
在本文中,我們深入探討了動(dòng)態(tài)SQL的各種標(biāo)簽,包括<if>、<choose>、<trim>、<foreach>等,通過(guò)實(shí)際的例子演示了它們的用法,感興趣的朋友一起揭開(kāi)動(dòng)態(tài)SQL的神秘面紗,帶你領(lǐng)略它的魅力2024-01-01