Spring Event觀察者模式事件監(jiān)聽詳解
Spring Event事件監(jiān)聽
Spring Event(Application Event)其實就是一個觀察者設(shè)計模式,一個 Bean 處理完成任務(wù)后希望通知其它 Bean 或者說一個 Bean 想觀察監(jiān)聽另一個Bean 的行為。在開發(fā)中我們經(jīng)常就會遇到修改一個bean時,同時需要去修改其他得bean?;蛘哒f當一個bean得值發(fā)生變化時,需要修改另一個bean得業(yè)務(wù)。還有一些業(yè)務(wù)場景不需要在一次請求中同步完成,比如郵件發(fā)送、短信發(fā)送等。
MQ 確實可以解決這個問題,但 MQ比較重,非必要不提升架構(gòu)復(fù)雜度。因此Spring Event是非常好得選擇。
依賴:引入Spring得核心依賴即可
Spring Event同步使用
自定義事件
定義事件,繼承 ApplicationEvent 的類成為一個事件類:
@Data
public class OrderProductEvent extends ApplicationEvent {
/** 該類型事件攜帶的信息 */
private String orderId;
public OrderProductEvent(Object source, String orderId) {
super(source);
this.orderId = orderId;
}
}定義監(jiān)聽器
監(jiān)聽并處理事件,實現(xiàn) ApplicationListener 接口或者使用 @EventListener 注解:
/**
* 實現(xiàn) ApplicationListener 接口,并指定監(jiān)聽的事件類型
*/
@Slf4j
@Component
public class OrderProductListener implements ApplicationListener<OrderProductEvent> {
/**
* 使用 onApplicationEvent 方法對消息進行接收處理
*
* */
@SneakyThrows
@Override
public void onApplicationEvent(OrderProductEvent event) {
String orderId = event.getOrderId();
long start = System.currentTimeMillis();
Thread.sleep(2000);
long end = System.currentTimeMillis();
log.info("{}:校驗訂單商品價格耗時:({})毫秒", orderId, (end - start));
}
}定義發(fā)布者
發(fā)布事件,通過 ApplicationEventPublisher 發(fā)布事件:
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderService {
/** 注入ApplicationContext用來發(fā)布事件 */
private final ApplicationContext applicationContext;
/**
* 下單
*
* @param orderId 訂單ID
*/
public String buyOrder(String orderId) {
long start = System.currentTimeMillis();
// 1.查詢訂單詳情
// 2.檢驗訂單價格 (同步處理)
applicationContext.publishEvent(new OrderProductEvent(this, orderId));
long end = System.currentTimeMillis();
log.info("任務(wù)全部完成,總耗時:({})毫秒", end - start);
return "購買成功";
}
}
測試執(zhí)行
@SpringBootTest
public class OrderServiceTest {
@Autowired
private OrderService orderService;
@Test
public void buyOrderTest() {
orderService.buyOrder("732171109");
}
}c.l.l.event.OrderProductListener : 732171109:校驗訂單商品價格耗時:(2001)毫秒
c.llp.llpspringretry.event.OrderService : 任務(wù)全部完成,總耗時:(2005)毫秒
Debug執(zhí)行流程




Spring Event 異步使用
有些業(yè)務(wù)場景不需要在一次請求中同步完成,比如郵件發(fā)送、短信發(fā)送等。
自定義事件
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class MsgEvent {
/** 該類型事件攜帶的信息 */
public String orderId;
}定義監(jiān)聽器
推薦使用 @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("開發(fā)發(fā)送短信");
log.info("開發(fā)發(fā)送郵件");
Thread.sleep(4000);
long end = System.currentTimeMillis();
log.info("{}:發(fā)送短信、郵件耗時:({})毫秒", orderId, (end - start));
}
}
定義發(fā)布者
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderService {
/** 注入ApplicationContext用來發(fā)布事件 */
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.短信通知(異步處理) 新開線程執(zhí)行監(jiān)聽得業(yè)務(wù)
applicationContext.publishEvent(new MsgEvent(orderId));
long end = System.currentTimeMillis();
log.info("任務(wù)全部完成,總耗時:({})毫秒", end - start);
return "購買成功";
}
}開啟異步支持
@EnableAsync開啟異步支持
@EnableAsync
@EnableRetry
@SpringBootApplication
public class LlpSpringRetryApplication {
public static void main(String[] args) {
SpringApplication.run(LlpSpringRetryApplication.class, args);
}
}
c.llp.llpspringretry.event.OrderService : 任務(wù)全部完成,總耗時:(6)毫秒
c.llp.llpspringretry.event.MsgListener : 開發(fā)發(fā)送短信
c.llp.llpspringretry.event.MsgListener : 開發(fā)發(fā)送郵件
到此這篇關(guān)于Spring Event觀察者模式事件監(jiān)聽詳解的文章就介紹到這了,更多相關(guān)Spring Event事件監(jiān)聽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java spring webmvc如何實現(xiàn)控制反轉(zhuǎn)
這篇文章主要介紹了Java spring webmvc如何實現(xiàn)控制反轉(zhuǎn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友可以參考下2020-08-08
springcloud中Feign超時提示Read timed out executing
Feign接口調(diào)用分兩層,Ribbon的調(diào)用和Hystrix調(diào)用,理論上設(shè)置Ribbon的時間即可,但是Ribbon的超時時間和Hystrix的超時時間需要結(jié)合起來,這篇文章給大家介紹springcloud之Feign超時提示Read timed out executing POST問題及解決方法,感興趣的朋友一起看看吧2024-01-01
SpringBoot中使用configtree讀取樹形文件目錄中的配置詳解
這篇文章主要介紹了SpringBoot中使用configtree讀取樹形文件目錄中的配置詳解,configtree通過spring.config.import?+?configtree:前綴的方式,加載以文件名為key、文件內(nèi)容為value的配置屬性,需要的朋友可以參考下2023-12-12
詳解Java編程中包package的內(nèi)容與包對象的規(guī)范
這篇文章主要介紹了Java編程中包package的內(nèi)容與包對象的規(guī)范,是Java入門學(xué)習中的基礎(chǔ)知識,需要的朋友可以參考下2015-12-12
Spring?Boot?中的?@DateTimeFormat?和?@JsonFormat?的用法及作用詳解
本文介紹了SpringBoot中的@DateTimeFormat和@JsonFormat注解的用法,解釋了它們在處理日期和時間數(shù)據(jù)時的作用,并通過實例代碼展示了如何在REST控制器中使用這些注解,感興趣的朋友跟隨小編一起看看吧2024-11-11

