Spring Event事件通知機制


Spring是基於事件驅動模型的,事件驅動模型也就是我們常說的觀察者,或者發布-訂閱模型。

Spring 的事件角色的類圖如下:

spring中的這些接口和抽象類:

  • ApplicationEventPublisherAware:接口,用來發布事件
  • ApplicationEvent :抽象類,用來定義事件
  • ApplicationListener<E extends ApplicationEvent>:接口,用來監聽事件,可以在這里實現自己的處理邏輯。
事件定義
/**
 * 定義事件
 */
public class UserRegisterEvent extends ApplicationEvent {
    public UserRegisterEvent(String name) { //name即source
        super(name);
    }
}
事件發布
@Service
public class UserService implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    public void register(String name) {
        System.out.println("用戶:" + name + " 已注冊!");
        applicationEventPublisher.publishEvent(new UserRegisterEvent(name));
    }

}

為了方便,我們可以單獨創建一個發布事件的類。

@Component
public class SpringEventHelper implements ApplicationEventPublisherAware {
    private static ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        if (null == SpringEventHelper.applicationEventPublisher) {
            SpringEventHelper.applicationEventPublisher = applicationEventPublisher;
        }
    }

    public static void publishEvent(ApplicationEvent event) {
        SpringEventHelper.applicationEventPublisher.publishEvent(event);
    }
}

這樣上面發布事件的代碼就改為:

@Service
public class UserService {

    public void register(String name) {
        System.out.println("用戶:" + name + " 已注冊!");
        SpringEventHelper.publishEvent(new UserRegisterEvent(name));
    }

}
事件訂閱(監聽者)
/**
 * 事件監聽者,可以自定義處理邏輯
 */
@Component
public class EmailHandler implements ApplicationListener<UserRegisterEvent> {
    @Override
    public void onApplicationEvent(UserRegisterEvent userRegisterEvent) {
        System.out.println("郵件服務接到通知,給 " + userRegisterEvent.getSource() + " 發送郵件...");
    }
}
基於注解的監聽@EventListener
@Component
public class SmsHandler{

    @EventListener
    public void createSmsEvent(UserRegisterEvent event){
        System.out.println("短信服務接到通知,給 " + event.getSource() + " 發送短信...");
    }
}
異步事件

上面的監聽事件都是同步觸發的,如果想異步只需要兩步:

  • 啟動類(SpringBoot)或Spring配置類上添加 @EnableAsync注解,開啟異步支持。
  • 所有事件監聽方法上添加 @Async注解
@Component
public class SmsHandler{

    @Async
    @EventListener
    public void createSmsEvent(UserRegisterEvent event){
        System.out.println("短信服務接到通知,給 " + event.getSource() + " 發送短信...");
    }
}
事件傳播機制

當我們監聽一個事件處理完成時,還需要發布另一個事件,一般我們想到的是調用ApplicationEventPublisher#publishEvent發布事件方法,但Spring提供了另一種更加靈活的新的事件繼續傳播機制,監聽方法返回一個事件,也就是方法的返回值就是一個事件對象。

假設現在有一個唱歌的事件和唱歌的監聽

/**
 * @Description 事件
 */
public class UserSingEvent extends ApplicationEvent {
    public UserSingEvent(String name) {
        super(name);
    }
}

/**
 * @Description 監聽者
 */
@Component
public class UserSingHandler {
    @EventListener
    public void createSingEvent(UserSingEvent event) {
        System.out.println("接到通知,給 " + event.getSource() + " 唱了一首【一剪梅】...");
    }
}

則上面發短信的事件訂閱者可以改為:

@Component
public class SmsHandler{

    @EventListener
    public UserSingEvent createSmsEvent(UserRegisterEvent event){
        System.out.println("短信服務接到通知,給 " + event.getSource() + " 發送短信...");
        String name = (String) event.getSource();
        return new UserSingEvent(name); // 發布另外一個事件
    }
}
完整示例:創建訂單

(1)訂單實體類

public class Order {

    private String orderNo;
    private String orderStatus;
    private String goods;
    private Date createTime;

    public String getOrderNo() {
        return orderNo;
    }

    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }

    public String getOrderStatus() {
        return orderStatus;
    }

    public void setOrderStatus(String orderStatus) {
        this.orderStatus = orderStatus;
    }

    public String getGoods() {
        return goods;
    }

    public void setGoods(String goods) {
        this.goods = goods;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}

(2)創建訂單的事件定義

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;
    }
}

(3)發布事件

@Service
public class OrderService {

    /**
     * 訂單保存
     */
    public void save() {
        Order order = new Order();
        order.setOrderNo("1");
        order.setGoods("手機");
        System.out.println("訂單保存成功:" + order.toString());
        //發布事件
        SpringEventHelper.publishEvent(new OrderCreateEvent(this, order));
    }
}

(4)事件訂閱

@Component
public class OrderCreateEventListener implements ApplicationListener<OrderCreateEvent> {

    @Override
    public void onApplicationEvent(OrderCreateEvent event) {
        System.out.printf(this.getClass().getName() + " -- ApplicationListener 接口實現,訂單號[%s]:,商品[%s]\n",
                event.getOrder().getOrderNo(), event.getOrder().getGoods());
    }
}

(5)測試

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class})
@WebAppConfiguration //全注解的形式必須添加@WebAppConfiguration注解
public class ContextTest {

    @Autowired
    private OrderService orderService;

    @Test
    public void test(){
        orderService.save();
    }

}

 參考

https://www.cnblogs.com/wuzhenzhao/p/12859876.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM