观察者模式在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));

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值