Spring 事件驅(qū)動(dòng)模型
0x01:spring事件驅(qū)動(dòng)組成
spring事件驅(qū)動(dòng)由3個(gè)部分組成
ApplicationEvent:表示事件本身,自定義事件需要繼承該類。用來(lái)定義事件
ApplicationEventPublisherAware:事件發(fā)送器,需要實(shí)現(xiàn)該接口。主要用來(lái)發(fā)布事件。ApplicationContext 也實(shí)現(xiàn)了該接口,可以用于發(fā)布事件。
Spring4.2之后,ApplicationEventPublisher自動(dòng)被注入到容器中,采用 Autowired 即可獲取。
ApplicationListener:事件監(jiān)聽(tīng)器接口。監(jiān)聽(tīng)類實(shí)現(xiàn) ApplicationListener 里onApplicationEvent方法即可。
在 spring4.2 以后可以以更加簡(jiǎn)潔的方式來(lái)監(jiān)聽(tīng) event 的發(fā)布,監(jiān)聽(tīng)事件不必再實(shí)現(xiàn) ApplicationListener 接口了,只要在方法上添加注解 @EventListener即可。
0x02:使用步驟詳解
Spring中使用事件非常簡(jiǎn)單,只需要以下的幾個(gè)步驟:
定義事件:繼承 ApplicationEvent
定義監(jiān)聽(tīng):要么實(shí)現(xiàn) ApplicationListener 接口,要么在方法上添加 @EventListener 注解
發(fā)布事件:調(diào)用 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、發(fā)送事件:publishEvent()方法
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void save(Order order) {
//生成訂單號(hào)
String orderNo = getOrderNo();
order.setOrderNo(orderNo);
log.info("訂單保存成功:" + order);
//發(fā)布訂單創(chuàng)建事件
applicationEventPublisher.publishEvent(new OrderCreateEvent(this, order));
}3、訂閱事件(實(shí)現(xiàn)觀察者有2種方式)
方式一:實(shí)現(xiàn) ApplicationListener 接口
@Component
public class OrderCreateEventListener implements ApplicationListener<OrderCreateEvent> {
@Override
public void onApplicationEvent(OrderCreateEvent event) {
System.out.printf("實(shí)現(xiàn)ApplicationListener接口,監(jiān)聽(tīng)OrderCreateEvent事件");
}
}方式二:通過(guò)@EventListener注解,該會(huì)根據(jù)方法參數(shù)類型來(lái)自動(dòng)監(jiān)聽(tīng)相應(yīng)事件的發(fā)布。
@Component
@Slf4j
public class OrderCreateEventListener {
@EventListener (classes = {OrderCreateEvent.class}) //classes屬性指定處理事件的類型
@Async //異步監(jiān)聽(tīng)
@Order(0)//使用order指定順序,越小優(yōu)先級(jí)越高
public void eventListener(OrderCreateEvent event) {
log.info("通過(guò)注解@EventListener和@Async,異步監(jiān)聽(tīng)OrderCreateEvent事件,orderId:" + event.getOrder().getOrderNo());
}
}如果要監(jiān)聽(tīng)多個(gè)事件類型的發(fā)布,可以在@EventListener(classes = {FaceEvent.class, ArmEvent.class})指定,spring 會(huì)多次調(diào)用此方法來(lái)處理多個(gè)事件。但是注意此時(shí),方法參數(shù)不能有多個(gè),否則會(huì)發(fā)生轉(zhuǎn)換異常,可以將使用多個(gè)事件的父類作為唯一的方法參數(shù)來(lái)接收處理事件,但除非必要否則并不推薦監(jiān)聽(tīng)多個(gè)事件的發(fā)布。
如果有多個(gè)監(jiān)聽(tīng)器監(jiān)聽(tīng)同一事件,可以在方法上使用 spring 的 @order 注解來(lái)定義多個(gè)監(jiān)聽(tīng)器的順序,order越小,優(yōu)先級(jí)越高。
@EventListener 還有一個(gè)屬性,condition()里可以使用 SPEL 表達(dá)式來(lái)過(guò)濾監(jiān)聽(tīng)到事件,即只有符合某種條件的才進(jìn)行接收處理。比如:
@EventListener(condition = "event.message == 'message'")監(jiān)聽(tīng)多個(gè)事件:
@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());
}
}注意事項(xiàng)
事件沒(méi)要處理的監(jiān)聽(tīng)器,就會(huì)被拋棄。
一個(gè)事件可以同時(shí)被多個(gè)監(jiān)聽(tīng)處理類監(jiān)聽(tīng)處理。
默認(rèn)情況下事件是同步的,即事件被 publish 后會(huì)等待 Listener 的處理。如果發(fā)布事件處的業(yè)務(wù)存在事務(wù),監(jiān)聽(tīng)器處理也會(huì)在相同的事務(wù)中。
如果對(duì)于事件的處理不想受到影響,可以onApplicationEvent方法上加@Async支持異步或者在有@EventListener的注解方法上加上@Async。注:?jiǎn)?dòng)類上同時(shí)要加上@EnableAsync
利用@TransactionalEventListener實(shí)現(xiàn)監(jiān)聽(tīng)事件時(shí)的事務(wù)隔離
很多時(shí)候,只有事務(wù)提交之后才會(huì)發(fā)布相應(yīng)的事件處理其他邏輯,比如用戶注冊(cè)之后,發(fā)送郵件或者短信。這時(shí)候就可以用注解 @TransactionalEventListener。
@TransactionalEventListener 和 @EventListener 都可以監(jiān)聽(tīng)事件,但前者可以對(duì)發(fā)布事件和監(jiān)聽(tīng)事件進(jìn)行一些事務(wù)上的隔離。
@TransactionalEventListener 是對(duì) @EventListener的一個(gè)擴(kuò)展,允許將事件的監(jiān)聽(tīng)器綁定到事務(wù)的某個(gè)階段。可以綁定到以下事務(wù)階段:
AFTER_COMMIT (默認(rèn)):事務(wù)提交后
AFTER_ROLLBACK ):事務(wù)回滾后
AFTER_COMPLETION ):事務(wù)完成,包括提交后和回滾后
BEFORE_COMMIT ):事務(wù)提交前
@TransactionalEventListener 指不和發(fā)布事件的方法在同一個(gè)事務(wù)內(nèi),發(fā)布事件的方法事務(wù)結(jié)束后才會(huì)執(zhí)行本監(jiān)聽(tīng)方法,監(jiān)聽(tīng)邏輯內(nèi)發(fā)生異常不會(huì)回滾發(fā)布事件方法的事務(wù)。
@TransactionalEventListener有一個(gè)屬性為 fallbackExecution,默認(rèn)為 false,指發(fā)布事件的方法沒(méi)有事務(wù)控制時(shí),監(jiān)聽(tīng)器不進(jìn)行監(jiān)聽(tīng)事件,此為默認(rèn)情況! fallbackExecution=true,則指發(fā)布事件的方法沒(méi)有事務(wù)控制時(shí),監(jiān)聽(tīng)方法仍可以監(jiān)聽(tīng)事件進(jìn)行處理。
source: https://blog.csdn.net/kaihuishang666/article/details/107520480

喜歡,在看
