觀察者模式在Spring中的應用

觀察者模式在Spring中的主要體現在事件監聽,事件機制的實現需要三個部分,事件源,事件,事件監聽器;
1 ApplicationEvent抽象類作爲事件的父類,通過source獲取事件源。

public abstract class ApplicationEvent extends EventObject {
    private static final long serialVersionUID = 7099057708183571937L;
    private final long timestamp = System.currentTimeMillis();

    public ApplicationEvent(Object source) {
        super(source);
    }

    public final long getTimestamp() {
        return this.timestamp;
    }
}

2 ApplicationListener接口作爲事件監聽器,繼承自EventListener

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E event);
}

3 ApplicationContext接口作爲事件源,在這裏可以將監聽器註冊進應用上下文中,也可以觸發指定的事件。在ApplicationContext的父類ApplicationEventPublisher中有這樣一個方法publishEvent,用以發佈事件,具體的實現類在AbstractApplicationContext中。

default void publishEvent(ApplicationEvent event) {
        this.publishEvent((Object)event);
    }

    void publishEvent(Object var1);

同樣在AbstractApplicationContext中有方法registerListeners,可以註冊監聽器。

    protected void registerListeners() {  
    // Register statically specified listeners first.  
    for (ApplicationListener<?> listener : getApplicationListeners()) {  
    getApplicationEventMulticaster().addApplicationListener(listener);  
    }  
    // Do not initialize FactoryBeans here: We need to leave all regular beans  
    // uninitialized to let post-processors apply to them!  
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);  
    for (String lisName : listenerBeanNames) {  
    getApplicationEventMulticaster().addApplicationListenerBean(lisName);  
    }  
  }  

下面模擬Spring的監聽器原理自己實現一個登陸登出事件的監聽機制。
1 事件類(ApplicationEvent)

@Data
public class Event implements Serializable {
    //事件源,誰觸發的
    private Object source;
    //觸發類型的標記
    private String trigger;
    //通知的目標對象
    private Object  target;
    //通知的目標的方法
    private Method callback;

    //觸發時間
    private long time;

    public Event() {
    }

    public Event(Object target, Method callback) {
        this.target = target;
        this.callback = callback;
    }
}

2 事件監聽抽象類,或者接口(ApplicationListener)

/**
 * 事件監聽器
 */
@Slf4j
public abstract class EventListener {
    /**
     * 存放事件
     */
    private List<Event> eventList = new ArrayList<>();

    /**
     * 添加事件監聽
     */
    public void addEvent(Object target, Method method) {
        Event event = new Event(target, method);
        eventList.add(event);
    }

    /**
     * 刪除事件監聽
     */
    public void removeEvent(Event e) {
        eventList.remove(e);
    }

    /**
     * 通過事件觸發
     */
    public void trigger(Event event) {
        event.setSource(this);
        event.setTime(System.currentTimeMillis());
        try {
            //調用指定的方法
            event.getCallback().invoke(event.getTarget(), event);
        } catch (Exception e) {
            log.info(e.getMessage());
        }
    }

    /**
     * 通過事件 類型出發,存儲事件的集合可以使用Map,自定義類型屬性
     */
}

3 具體事件,繼承自事件監聽抽象類(ApplicationContext)

/**
 * 實例對象,具體的被觀察者,即被監聽的事件實現類
 */
public class ConcreteSubject extends EventListener {

    /**
     * 模擬登陸推出,異常事件監聽
     */
    public void login(Event loginEvent) {
        System.out.println("登陸事件");
        super.trigger(loginEvent);
    }

    public void logout(Event logoutEvent) {
        System.out.println("登出事件");
        super.trigger(logoutEvent);
    }

    public void exception(Event exceptionEvent) {
        System.out.println("異常事件");
        super.trigger(exceptionEvent);
    }

}

4 對於監聽到指定事件給出相應的反饋類

/**
 * 觀察者方法,模擬觀察者觀察到指定事件後相應的動作
 */
public class LogEventCallback {

    public void login(Event event) {
        System.out.println("=======用戶登陸======" + event);
    }

    public void logout(Event event) {
        System.out.println("=======用戶登出======" + event);
    }

    public void exception(Event event) {
        System.out.println("=======異常======" + event);
    }
}

5 測試類,測試登陸事件的監聽機制

public class LogEventTest {

    public static void main(String[] args) throws NoSuchMethodException {
        LogEventCallback target = new LogEventCallback();
        //通過反射獲取指定的方法
        Method login = target.getClass().getDeclaredMethod("login", Event.class);
        Method logout = target.getClass().getDeclaredMethod("logout", Event.class);
        Method exception = target.getClass().getDeclaredMethod("exception", Event.class);
        ConcreteSubject object = new ConcreteSubject();
        //將監聽事件放進監聽類中,與Spring中的ApplicationContext功能相同
        object.addEvent(target, logout);
        object.addEvent(target, login);
        object.addEvent(target, exception);

        object.trigger(new Event(target, login));

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