Spring Event 快速入門

請直接看原文?:

Spring Event,賊好用的業務解耦神器! (qq.com)

--------------------------------------------------------------------------------------------------------------------------------?

  • 前言

  • Spring Event 同步使用

  • Spring Event 異步使用

前言

實際業務開發過程中,業務邏輯可能非常復雜,核心業務 + N 個子業務。如果都放到一塊兒去做,代碼可能會很長,耦合度不斷攀升,維護起來也麻煩,甚至頭疼。還有一些業務場景不需要在一次請求中同步完成,比如郵件發送、短信發送等。

?MQ 確實可以解決這個問題,但 MQ 重啊,非必要不提升架構復雜度。針對這些問題,我們了解一下 Spring Event。

Spring Event 同步使用

Spring Event(Application Event)其實就是一個觀察者設計模式,一個 Bean 處理完成任務后希望通知其它 Bean 或者說一個 Bean 想觀察監聽另一個Bean 的行為。

Spring Event 用來解耦業務真的賊好用!

| 自定義事件

定義事件,繼承 ApplicationEvent 的類成為一個事件類:

import lombok.Data;
import lombok.ToString;
import org.springframework.context.ApplicationEvent;/*** @author Strive* @date 2022/4/22 18:00* @description*/
@Data
@ToString
public class OrderProductEvent extends ApplicationEvent {/** 該類型事件攜帶的信息 */private String orderId;public OrderProductEvent(Object source, String orderId) {super(source);this.orderId = orderId;}
}
| 定義監聽器

監聽并處理事件,實現 ApplicationListener 接口或者使用?@EventListener 注解:

import com.csp.mingyue.event.events.OrderProductEvent;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;/*** 實現 ApplicationListener 接口,并指定監聽的事件類型** @author Strive* @date 2022/4/24 09:09* @description*/
@Slf4j
@Component
public class OrderProductListener implements ApplicationListener<OrderProductEvent> {/** 使用 onApplicationEvent 方法對消息進行接收處理 */@SneakyThrows@Overridepublic void onApplicationEvent(OrderProductEvent event) {String orderId = event.getOrderId();long start = System.currentTimeMillis();Thread.sleep(2000);long end = System.currentTimeMillis();log.info("{}:校驗訂單商品價格耗時:({})毫秒", orderId, (end - start));}
}
| 定義發布者

發布事件,通過 ApplicationEventPublisher 發布事件:

import com.csp.mingyue.event.events.OrderProductEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;/*** @author Strive* @date 2022/4/24 09:25* @description*/
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderService {/** 注入ApplicationContext用來發布事件 */private final ApplicationContext applicationContext;/*** 下單** @param orderId 訂單ID*/public String buyOrder(String orderId) {long start = System.currentTimeMillis();// 1.查詢訂單詳情// 2.檢驗訂單價格 (同步處理)applicationContext.publishEvent(new OrderProductEvent(this, orderId));// 3.短信通知(異步處理)long end = System.currentTimeMillis();log.info("任務全部完成,總耗時:({})毫秒", end - start);return "購買成功";}
}

?| 單測執行

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;/*** @author Strive* @date 2022/4/24 09:28* @description*/
@SpringBootTest
public class OrderServiceTest {@Autowired private OrderService orderService;@Testpublic void buyOrderTest() {orderService.buyOrder("732171109");}
}

執行結果如下:

2022-04-24 10:13:17.535  INFO 44272 --- [           main] c.c.m.e.listener.OrderProductListener    : 732171109:校驗訂單商品價格耗時:(2008)毫秒
2022-04-24 10:13:17.536  INFO 44272 --- [           main] c.c.mingyue.event.service.OrderService   : 任務全部完成,總耗時:(2009)毫秒

?Spring Event 異步使用

有些業務場景不需要在一次請求中同步完成,比如郵件發送、短信發送等。

| 自定義事件
import lombok.AllArgsConstructor;
import lombok.Data;/*** @author Strive* @date 2022/4/24 10:18* @description*/
@Data
@AllArgsConstructor
public class MsgEvent {/** 該類型事件攜帶的信息 */public String orderId;
}
| 定義監聽器

推薦使用?@EventListener 注解:

import com.csp.mingyue.event.events.MsgEvent;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;/*** @author Strive* @date 2022/4/24 10:20* @description*/
@Slf4j
@Component
public class MsgListener {@SneakyThrows@EventListener(MsgEvent.class)public void sendMsg(MsgEvent event) {String orderId = event.getOrderId();long start = System.currentTimeMillis();log.info("開發發送短信");log.info("開發發送郵件");Thread.sleep(4000);long end = System.currentTimeMillis();log.info("{}:發送短信、郵件耗時:({})毫秒", orderId, (end - start));}
}
| 定義發布者
/***?下單**?@param?orderId?訂單ID*/
public?String?buyOrder(String?orderId)?{long?start?=?System.currentTimeMillis();//?1.查詢訂單詳情//?2.檢驗訂單價格?(同步處理)applicationContext.publishEvent(new?OrderProductEvent(this,?orderId));//?3.短信通知(異步處理)applicationContext.publishEvent(new?MsgEvent(orderId));long?end?=?System.currentTimeMillis();log.info("任務全部完成,總耗時:({})毫秒",?end?-?start);return?"購買成功";
}

| 單測執行(同步)

@Test
public?void?buyOrderTest()?{orderService.buyOrder("732171109");
}

執行結果如下:

2022-04-24?10:24:13.905??INFO?54848?---?[???????????main]?c.c.m.e.listener.OrderProductListener????: 732171109:校驗訂單商品價格耗時:(2004)毫秒
2022-04-24?10:24:13.906??INFO?54848?---?[???????????main]?c.c.mingyue.event.listener.MsgListener???:?開發發送短信
2022-04-24?10:24:13.907??INFO?54848?---?[???????????main]?c.c.mingyue.event.listener.MsgListener???:?開發發送郵件
2022-04-24?10:24:17.908??INFO?54848?---?[???????????main]?c.c.mingyue.event.listener.MsgListener???: 732171109:發送短信、郵件耗時:(4002)毫秒
2022-04-24?10:24:17.908??INFO?54848?---?[???????????main]?c.c.mingyue.event.service.OrderService???:?任務全部完成,總耗時:(6008)毫秒
| 開啟異步

啟動類增加?@EnableAsync 注解:

@EnableAsync
@SpringBootApplication
public?class?MingYueSpringbootEventApplication?{public?static?void?main(String[]?args)?{SpringApplication.run(MingYueSpringbootEventApplication.class,?args);}
}

Listener 類需要開啟異步的方法增加?@Async 注解:

@Async
@SneakyThrows
@EventListener(MsgEvent.class)
public?void?sendMsg(MsgEvent?event)?{String?orderId?=?event.getOrderId();long?start?=?System.currentTimeMillis();log.info("開發發送短信");log.info("開發發送郵件");Thread.sleep(4000);long?end?=?System.currentTimeMillis();log.info("{}:發送短信、郵件耗時:({})毫秒",?orderId,?(end?-?start));
}
| 單測執行(異步)

發送短信的線程顯示 task-1,主線程結束后(總耗時:(2017)毫秒)控制臺停止打印了:

2022-04-24?10:30:59.002??INFO?59448?---?[???????????main]?c.c.m.e.listener.OrderProductListener????: 732171109:校驗訂單商品價格耗時:(2009)毫秒
2022-04-24?10:30:59.009??INFO?59448?---?[???????????main]?c.c.mingyue.event.service.OrderService???:?任務全部完成,總耗時:(2017)毫秒
2022-04-24?10:30:59.028??INFO?59448?---?[?????????task-1]?c.c.mingyue.event.listener.MsgListener???:?開發發送短信
2022-04-24?10:30:59.028??INFO?59448?---?[?????????task-1]?c.c.mingyue.event.listener.MsgListener???:?開發發送郵件

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/697769.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/697769.shtml
英文地址,請注明出處:http://en.pswp.cn/news/697769.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

架構篇35:微服務架構最佳實踐 - 方法篇

文章目錄 服務粒度拆分方法基礎設施小結上一篇我們談了實施微服務需要避免踩的陷阱,簡單提煉為: 微服務拆分過細,過分強調“small”。微服務基礎設施不健全,忽略了“automated”。微服務并不輕量級,規模大了后,“lightweight”不再適應。針對這些問題,我們看看微服務最佳…

ADAS智能駕駛測試知多少?

當涉及ADAS&#xff08;Advanced Driver Assistance Systems&#xff09;智能駕駛的測試時&#xff0c;有一個完整的測試體系可以用來評估系統的性能和功能。 1. 傳感器測試 1.1 傳感器校準測試 描述&#xff1a;確保傳感器&#xff08;如雷達、攝像頭、激光雷達等&#xff09;…

【stm32】hal庫學習筆記-UART/USART串口通信(超詳細!)

【stm32】hal庫學習筆記-UART/USART串口通信 hal庫驅動函數 CubeMX圖形化配置 導入LCD.ioc RTC設置 時鐘樹配置 設置LSE為RTC時鐘源 USART設置 中斷設置 程序編寫 編寫主函數 /* USER CODE BEGIN 2 */lcd_init();lcd_show_str(10, 10, 16, "Demo12_1:USART1-CH340&q…

【PythonGIS】Python線矢量等距離取點/線等分取點點創建矢量面

不多說&#xff0c;這是之前項目需求的代碼&#xff0c;已經是去年的了一直沒來的及發&#xff0c;今天抽出來一丟丟的空擋發一下。主要就是利用線矢量等距離生成點矢量&#xff0c;或者直接將線矢量等分生成點矢量&#xff0c;這個需求其實極限一下就是線轉點了&#xff08;將…

Java中各種O(PO,BO,DTO,VO等) 是不是人為增加系統復雜度?

Java中各種O(PO,BO,DTO,VO等) 是不是人為增加系統復雜度&#xff1f; 在Java和其他編程語言的開發過程中&#xff0c;經常會用到幾個以"O"結尾的縮寫&#xff0c;比如PO,BO,DTO,VO等等&#xff0c;O在這里是Object的縮寫&#xff0c;不同的O代表了不同的數據類型&am…

onlyoffice7.5.1 實現填寫表單 word+html form雙向綁定功能

說明&#xff1a;目前官方已經更新wordhtml為8.0以前的&#xff0c;目前官方新版本8.0增加了pdf綁定&#xff0c;這個我考慮在以后研究努力實現。 onlyoffice雙向綁定form表單數據

Java基礎 - 13 Queue之DelayQueue、PriorityQueue、PriorityBlockingQueue講解

在Java的隊列世界里&#xff0c;有三位大佬&#xff0c;他們分別是DelayQueue、PriorityQueue和PriorityBlockingQueue。今天&#xff0c;讓我們一起揭開他們神秘的面紗&#xff0c;看看他們各自的特點和用途吧&#xff01; DelayQueue 首先&#xff0c;讓我們來認識一下Delay…

2.22 作業

順序表 運行結果 fun.c #include "fun.h" seq_p create_seq_list() {seq_p L (seq_p)malloc(sizeof(seq_list));if(LNULL){printf("空間申請失敗\n");return NULL;}L->len 0; bzero(L,sizeof(L->data)); return L; } int seq_empty(seq_p L) {i…

工廠方法模式Factory Method

1.模式定義 定義一個用于創建對象的接口&#xff0c;讓子類決定實例化哪一個類。Factory Method 使得一個類的實例化延遲到子類 2.使用場景 1.當你不知道改使用對象的確切類型的時候 2.當你希望為庫或框架提供擴展其內部組件的方法時 主要優點&#xff1a; 1.將具體產品和創建…

PHP+vue+mysql倉庫進銷存管理系統8jeqj

開發語言&#xff1a;php 后端框架&#xff1a;Thinkphp 前端框架&#xff1a;vue.js 服務器&#xff1a;apache 數據庫&#xff1a;mysql 運行環境:phpstudy/wamp/xammp等 數據庫工具&#xff1a;Navicat/phpmyadmin 登錄模塊&#xff1a;此模塊主要有4個部分&#xff0c;基…

實驗中用戶行為的檢測

[1] Makris S , Karagiannis P , Koukas S ,et al.Augmented reality system for operator support in human–robot collaborative assembly[J].CIRP Annals - Manufacturing Technology, 2016:S0007850616300385.DOI:10.1016/j.cirp.2016.04.038. —————————————…

gem5學習(24):緩存一致性協議——Cache Coherence Protocols

目錄 一、Common Notations and Data Structures 1、Coherence Messages 2、Access Permissions 3、Data Structures 二、Coherence controller FSM Diagrams 官網教程&#xff1a;gem5: Cache Coherence Protocols 一、Common Notations and Data Structures &#xff…

什么是SSD型云服務器?

?  SSD云服務器是一種使用固態硬盤代替傳統HDD進行存儲的虛擬機。SDD 使用閃存單元來存儲數據&#xff0c;與云計算技術相結合&#xff0c;形成強大且高效的存儲解決方案&#xff0c;可以隨時隨地訪問。 SSD云服務器如何工作? SSD云服務器是利用虛擬化和云計算技術創建的。…

C++最佳實踐之編譯篇

C最佳實踐之工程編譯 在大型c/c工程開發中&#xff0c;往往會涉及多級CMakeLists.txt的調用&#xff0c;并且調用方式錯綜復雜&#xff0c;主要有以下兩種方式&#xff1a; 1. 子目錄中的CMakeList.txt獨立生成目標&#xff0c;不作為主目標生成過程的依賴關系&#xff08;比…

virtualenv env_name 使用 virtualenv 創建 python 虛擬環境

為什么要用這個 win7 32 環境下 pycharm 只能用低版本的&#xff0c;比如 2016,2018 此時pycharm 圖形界面創建的 虛擬環境版本很低&#xff0c;有些包不兼容&#xff0c;因此用 virtualenv 模塊&#xff0c;可以創建 20 版本以上的虛擬環境 virtualenv env_name官方文檔 http…

如何選擇最適合的圖紙加密軟件?安秉網盾軟件用戶體驗及性價比

安秉網盾圖紙加密軟件是一款功能強大的圖紙加密工具&#xff0c;具有以下特點和優勢&#xff1a; 全盤加密&#xff1a;安秉網盾采用先進的加密算法&#xff0c;能對文件、文件夾、磁盤等數據進行全面加密&#xff0c;確保數據在存儲和傳輸過程中的安全性。 監控與審計&#x…

Swift基礎知識:26.Swift類型轉換

在 Swift 中&#xff0c;類型轉換是指將一種類型的實例轉換為另一種類型的操作。Swift 提供了三種類型轉換操作&#xff1a;as?、as! 和 is。 as? 和 as! as?&#xff1a;可選類型轉換。如果轉換成功&#xff0c;返回一個可選類型&#xff0c;值為轉換后的類型&#xff1b…

編程筆記 Golang基礎 024 映射

編程筆記 Golang基礎 024 映射 一、映射二、映射的定義與初始化三、基本操作四、綜合示例程序 Go語言中的映射&#xff08;map&#xff09;是一種關聯數組或哈希表數據結構&#xff0c;它存儲鍵值對&#xff0c;其中每個鍵都是唯一的。在Go中&#xff0c;你可以使用 map[keyTy…

關于el-select值的回顯問題 : 框內顯示label值還是value值

<el-form-item label"狀態" prop""><el-selectv-model"roleForm.state"class"m-2"size"large"style"width: 240px"placeholder"請選擇狀態"value-key"value"//value-key 與下面的ke…

How to implement multiple file uploads based on Swagger 3.x in Spring boot 3.x

How to implement multiple file uploads based on Swagger 3.x in Spring boot 3.x Projectpom.xmlOpenAPIConfigFileUploadControllerapplication.yaml Project pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://…