Spring 事件驅動模型
0x01:spring 事件驅動組成
spring 事件驅動由 3 個部分組成
-
ApplicationEvent:表示事件本身,自定義事件需要繼承該類。用來定義事件
-
ApplicationEventPublisherAware:事件發送器,需要實現該接口。主要用來發布事件。ApplicationContext 也實現了該接口,可以用於發佈事件。
Spring4.2 之後,ApplicationEventPublisher 自動被注入到容器中,採用 Autowired 即可獲取。
- ApplicationListener:事件監聽器接口。監聽類實現 ApplicationListener 裏 onApplicationEvent 方法即可。
在 spring4.2 以後可以以更加簡潔的方式來監聽 event 的發佈,監聽事件不必再實現 ApplicationListener 接口了,只要在方法上添加註解 @EventListene r 即可。
0x02:使用步驟詳解
Spring 中使用事件非常簡單,只需要以下的幾個步驟:
-
定義事件:繼承 ApplicationEvent
-
定義監聽:要麼實現 ApplicationListener 接口,要麼在方法上添加 @EventListener 註解
-
發佈事件:調用 ApplicationContext.publishEvent() 或者 ApplicationEventPublisher.publishEvent()
1、定義事件
public class OrderCreateEvent extends ApplicationEvent {
private final Order order;
public OrderCreateEvent(Object source, Order order) {
super(source);
this.order = order;
}
public Order getOrder() {
return order;
}
}
2、發送事件:publishEvent() 方法
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void save(Order order) {
//生成訂單號
String orderNo = getOrderNo();
order.setOrderNo(orderNo);
log.info("訂單保存成功:" + order);
//發佈訂單創建事件
applicationEventPublisher.publishEvent(new OrderCreateEvent(this, order));
}
3、訂閱事件(實現觀察者有 2 種方式)
- 方式一:實現 ApplicationListener 接口
@Component
public class OrderCreateEventListener implements ApplicationListener<OrderCreateEvent> {
@Override
public void onApplicationEvent(OrderCreateEvent event) {
System.out.printf("實現ApplicationListener接口,監聽OrderCreateEvent事件");
}
}
- 方式二:通過 @EventListener 註解, 該會根據方法參數類型來自動監聽相應事件的發佈。
@Component
@Slf4j
public class OrderCreateEventListener {
@EventListener (classes = {OrderCreateEvent.class}) //classes屬性指定處理事件的類型
@Async //異步監聽
@Order(0)//使用order指定順序,越小優先級越高
public void eventListener(OrderCreateEvent event) {
log.info("通過註解@EventListener和@Async,異步監聽OrderCreateEvent事件,orderId:" + event.getOrder().getOrderNo());
}
}
如果要監聽多個事件類型的發佈,可以在 @EventListener(classes = {FaceEvent.class, ArmEvent.class}) 指定,spring 會多次調用此方法來處理多個事件。但是注意此時,方法參數不能有多個,否則會發生轉換異常,可以將使用多個事件的父類作爲唯一的方法參數來接收處理事件,但除非必要否則並不推薦監聽多個事件的發佈。
如果有多個監聽器監聽同一事件,可以在方法上使用 spring 的 @order 註解來定義多個監聽器的順序,order 越小,優先級越高。
@EventListener 還有一個屬性,condition()裏可以使用 SPEL 表達式來過濾監聽到事件,即只有符合某種條件的才進行接收處理。比如:
@EventListener(condition = "event.message == 'message'")
監聽多個事件:
@EventListener({FaceEvent.class,ArmEvent.class})
public void onApplicationEvent3(Object event) {
if(event instanceof FaceEvent){
LOGGER.info("===> B 收到人臉事件: {}",((FaceEvent) event).getEventData());
}else if(event instanceof ArmEvent){
ArmEvent armEvent = (ArmEvent) event;
LOGGER.info("===> B 收到臂膀事件: {}",armEvent.getEventData());
}
}
注意事項
-
事件沒要處理的監聽器,就會被拋棄。
-
一個事件可以同時被多個監聽處理類監聽處理。
-
默認情況下事件是同步的,即事件被 publish 後會等待 Listener 的處理。如果發佈事件處的業務存在事務,監聽器處理也會在相同的事務中。
-
如果對於事件的處理不想受到影響,可以 onApplicationEvent 方法上加 @Async 支持異步或者在有 @EventListener 的註解方法上加上 @Async。注:啓動類上同時要加上 @EnableAsync
利用 @TransactionalEventListener 實現監聽事件時的事務隔離
很多時候,只有事務提交之後纔會發佈相應的事件處理其他邏輯,比如用戶註冊之後,發送郵件或者短信。這時候就可以用註解 @TransactionalEventListener。
@TransactionalEventListener 和 @EventListener 都可以監聽事件,但前者可以對發佈事件和監聽事件進行一些事務上的隔離。
@TransactionalEventListener 是對 @EventListener 的一個擴展,允許將事件的監聽器綁定到事務的某個階段。可以綁定到以下事務階段:
-
AFTER_COMMIT (默認):事務提交後
-
AFTER_ROLLBACK ):事務回滾後
-
AFTER_COMPLETION ):事務完成,包括提交後和回滾後
-
BEFORE_COMMIT ):事務提交前
@TransactionalEventListener 指不和發佈事件的方法在同一個事務內,發佈事件的方法事務結束後纔會執行本監聽方法,監聽邏輯內發生異常不會回滾發佈事件方法的事務。
@TransactionalEventListener 有一個屬性爲 fallbackExecution,默認爲 false,指發佈事件的方法沒有事務控制時,監聽器不進行監聽事件,此爲默認情況! fallbackExecution=true,則指發佈事件的方法沒有事務控制時,監聽方法仍可以監聽事件進行處理。
source: https://blog.csdn.net/kaihuishang666/article/details/107520480
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/RjB4TcKeSos6825HjbkaNA