Spring 事件驅動模型

0x01:spring 事件驅動組成

spring 事件驅動由 3 個部分組成

Spring4.2 之後,ApplicationEventPublisher 自動被注入到容器中,採用 Autowired 即可獲取。

在 spring4.2 以後可以以更加簡潔的方式來監聽 event 的發佈,監聽事件不必再實現 ApplicationListener 接口了,只要在方法上添加註解 @EventListene r 即可。

0x02:使用步驟詳解

Spring 中使用事件非常簡單,只需要以下的幾個步驟:

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 種方式)

@Component
public class OrderCreateEventListener implements ApplicationListener<OrderCreateEvent> {
    @Override
    public void onApplicationEvent(OrderCreateEvent event) {
        System.out.printf("實現ApplicationListener接口,監聽OrderCreateEvent事件");
    }
}
@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());
        }
}

注意事項

利用 @TransactionalEventListener 實現監聽事件時的事務隔離

很多時候,只有事務提交之後纔會發佈相應的事件處理其他邏輯,比如用戶註冊之後,發送郵件或者短信。這時候就可以用註解 @TransactionalEventListener。

@TransactionalEventListener 和 @EventListener 都可以監聽事件,但前者可以對發佈事件和監聽事件進行一些事務上的隔離。

@TransactionalEventListener 是對 @EventListener 的一個擴展,允許將事件的監聽器綁定到事務的某個階段。可以綁定到以下事務階段:

@TransactionalEventListener 指不和發佈事件的方法在同一個事務內,發佈事件的方法事務結束後纔會執行本監聽方法,監聽邏輯內發生異常不會回滾發佈事件方法的事務。

@TransactionalEventListener 有一個屬性爲 fallbackExecution,默認爲 false,指發佈事件的方法沒有事務控制時,監聽器不進行監聽事件,此爲默認情況! fallbackExecution=true,則指發佈事件的方法沒有事務控制時,監聽方法仍可以監聽事件進行處理。

source: https://blog.csdn.net/kaihuishang666/article/details/107520480
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/RjB4TcKeSos6825HjbkaNA