設計模式套路3 基於 Spring 實現觀察者模式的最佳實踐

觀察者模式定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新,其主要解決一個對象狀態改變給其他關聯對象通知的問題,保證易用和低耦合。一個典型的應用場景是:當用戶註冊以後,需要給用戶發送郵件,發送優惠券等操作,如下圖所示。

UserService 在完成自身的用戶註冊邏輯之後,僅僅只需要發佈一個 UserRegisterEvent 事件,而無需關注其它拓展邏輯。其它 Service 可以自己訂閱 UserRegisterEvent 事件,實現自定義的拓展邏輯。Spring的事件機制主要由3個部分組成。

  • ApplicationEvent:通過繼承它,實現自定義事件。另外,通過它的 source 屬性可以獲取事件源,timestamp 屬性可以獲得發生時間。
  • ApplicationEventPublisher:通過實現它,來發布變更事件。
  • ApplicationEventListener:通過實現它,來監聽指定類型事件並響應動作。這裏就以上面的用戶註冊爲例,來看看代碼示例。首先定義用戶註冊事件 UserRegisterEvent。
publicclass UserRegisterEvent extends ApplicationEvent {
    /**
     * 用戶名
     */
    private String username;
    public UserRegisterEvent(Object source) {
        super(source);
    }
    public UserRegisterEvent(Object source, String username) {
        super(source);
        this.username = username;
    }
    public String getUsername() {
        return username;
    }
}

然後定義用戶註冊服務類,實現 ApplicationEventPublisherAware 接口,從而將 ApplicationEventPublisher 注入進來。從下面代碼可以看到,在執行完註冊邏輯後,調用了 ApplicationEventPublisher的 publishEvent(ApplicationEvent event) 方法,發佈了 UserRegisterEvent 事件。

@Service
publicclass UserService implements ApplicationEventPublisherAware { // <1>
    private Logger logger = LoggerFactory.getLogger(getClass());
    private ApplicationEventPublisher applicationEventPublisher;
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
    public void register(String username) {
        // ... 執行註冊邏輯
        logger.info("[register][執行用戶({}) 的註冊邏輯]", username);
        // <2> ... 發佈
        applicationEventPublisher.publishEvent(new UserRegisterEvent(this, username));
    }
}

創建郵箱Service,實現 ApplicationListener 接口,通過 E 泛型設置感興趣的事件,實現 onApplicationEvent(E event) 方法,針對監聽的 UserRegisterEvent 事件,進行自定義處理。

@Service
publicclass EmailService implements ApplicationListener<UserRegisterEvent> { // <1>
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Override
    @Async// <3>
    public void onApplicationEvent(UserRegisterEvent event) { // <2>
        logger.info("[onApplicationEvent][給用戶({}) 發送郵件]", event.getUsername());
    }
}

創建優惠券Service,不同於上面的實現 ApplicationListener 接口方式,在方法上,添加 @EventListener 註解,並設置監聽的事件爲 UserRegisterEvent。這是另一種使用方式。

@Service
publicclass CouponService {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @EventListener// <1>
    public void addCoupon(UserRegisterEvent event) {
        logger.info("[addCoupon][給用戶({}) 發放優惠劵]", event.getUsername());
    }
}

看到這裏,細心的同學可能想到了發佈訂閱模式,其實觀察者模式於發佈訂閱還是有區別的,簡單來說,發佈訂閱模式屬於廣義上的觀察者模式,在觀察者模式的 Subject 和 Observer 的基礎上,引入 Event Channel 這個中介,進一步解耦。圖示如下,可以看出,觀察者模式更加輕量,通常用於單機,而發佈訂閱模式相對而言更重一些,通常用於分佈式環境下的消息通知場景。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章