Spring 观察者模式详解以及自定义监听器扩展实现(上)

简介: Spring 观察者模式详解以及自定义监听器扩展实现

前言

在 Spring 运用中,观察者模式运用的场景很多,只不过在 Spring 内部为观察者模式定义为了抽象,使用多路广播器方式将观察者、被观察者、行为抽象了事件、监听器、事件源等名,下面对该内容进行详细分析

观察者模式/监听机制

监听器:模式中的观察者角色

多路广播器:被观察者触发事件调用,多个观察者监听到事件处理对应方法的逻辑

在 Spring 里面其实就是运用观察者模式进行设计的,它对比传统的观察者模式基础上进行了加工,概念上已经改为了基于事件驱动触发行为动作,下面对传统观察者模式、Spring 加工后的观察者模式进行介绍

观察者模式(传统)

观察者模式又称为发布/订阅(Publish/Subscribe)模式,在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新触发行为

观察者、被观察者共有行为

/**
 * 被观察者
 */
public interface Observable {
     public void addObserver(Observer observer);
     public void deleteObserver(Observer observer);
     public void notifyObserver(String str);
}
/**
 * 观察者
 */
public interface Observer {
    public void make(String str);
}

被观察者实现类

public class BadMan implements Observable {
    private ArrayList<Observer> observers = new ArrayList<Observer>();
    @Override
    public void addObserver(Observer observer) {
        this.observers.add(observer);
    }
    @Override
    public void deleteObserver(Observer observer) {
        this.observers.remove(observer);
    }
    @Override
    public void notifyObserver(String str) {
        for (Observer observer1 : observers) {
            observer1.make(str);
        }
    }
    public void run(){
        System.out.println("罪犯要逃跑了");
        this.notifyObserver("追击罪犯");
    }
    public void play(){
        System.out.println("罪犯在玩");
        this.notifyObserver("不动做任何事情,静观其变");
    }
}

观察者

public class Police implements Observer {
    @Override
    public void make(String str) {
        System.out.println("police(警察)开始行动");
        System.out.println("--------"+str);
    }
}
public class Soldier implements Observer {
    @Override
    public void make(String str) {
        System.out.println("军官(soldier)开始行动");
        System.out.println("====="+str);
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        // 创建被观察者
        BadMan bm = new BadMan();
        // 创建观察者
        Police gm = new Police();
        Soldier gm2 = new Soldier();
        // 向被观察者中添加观察者
        bm.addObserver(gm);
        bm.addObserver(gm2);
        // 等待罪犯触发某些行为
        bm.run();
    }
}

java.util 包下有提供 Observer 接口、Observable

  • 被观察者:存储一个观察者的集合,执行不同动作时,要调用观察者的方法进行处理
  • 观察者:看到被观察者不同行为的时候触发的反应

观察者模式(Spring)

在 Spring 中,观察者模式被理解为 “事件驱动”,通过对传统模式的理解进行细化拆分

基本概念

  • 事件:被观察者具体要执行的动作「代码中的 run、play 方法」被拆分成事件,所有事件都实现于 ApplicationEvent 接口,交给子类在不同的事件情况时去执行自己内部的逻辑
  • 监听器:作为观察者,可能存在多个,接受不同的事件去做不同的处理工作,所有监听器都实现于 ApplicationListener 接口,重写 onApplicationEvent 方法,方法内部通过不同的事件【ApplicationEvent】类型进行调用
  • 多播器:把被观察者遍历观察者列表通知的消息操作拿出来,委托给一个多播器来进行消息通知,或者说通过观察者进行不同的操作,一般是 ApplicationEventMulticaster 子类 SimpleApplicationEventMulticaster 进行事件广播操作
  • 事件源:谁来调用或者执行发布具体的事件,如在 AbstractApplicationContext 中调用 publishEvent(new ContextRefreshedEvent(this))发布事件,比如 AbstractApplicationContext 就是指的事件源,它实现了 ApplicationEventPublisher 接口,可以调用 publishEvent 方法,类图如下

事件驱动准备工作及执行过程

事件驱动的准备工作如下:

  • 提前准备好 N 多个事件
  • 初始化多播器(创建多播器对象,此多播器对象中应该包含一个监听器的集合)
  • 准备好一系列的监听器,向多播器中注册进去需要执行的监听器
  • 准备事件发布,通知多播器循环调用监听器 onApplicationEvent 方法进行相关的逻辑处理工作

Spring 相关的源码

初始化事件监听多路广播器

protected void initApplicationEventMulticaster() {
    // 获取当前bean工厂,一般是DefaultListableBeanFactory
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // 判断容器中是否存在bdName为applicationEventMulticaster的bd,也就是说自定义的事件监听多路广播器,必须实现ApplicationEventMulticaster接口
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        // 如果有,则从bean工厂得到这个bean对象
        this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        // 如果没有,则默认采用 SimpleApplicationEventMulticaster
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                         "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
        }
    }
}

默认采用的是 SimpleApplicationEventMulticaster 多路广播器,它的父类 AbstractApplicationEventMulticaster 内部类专门使用了一个集合来存储所有加载的监听器

// 创建监听器助手类,用于存放应用程序的监听器集合,参数是否是预过滤监听器为false
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
private class ListenerRetriever {
    // ApplicationListener 对象集合
    public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
    // BeanFactory 中的 applicationListener 类型 Bean 名集合
    // 在设置监听器时会通过 beanName 去获取监听器,再放入 applicationListeners 集合中
    public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
.......
}

注册监听器的源码:在所有注册的 bean 中查找监听器,将监听器注册到消息广播器中

protected void registerListeners() {
    // 遍历应用程序中存在的监听器集合,并将对应的监听器添加到监听器的多路广播器中
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }
    // 从容器中获取所有实现了ApplicationListener接口的bd的bdName
    // 放入 ApplicationListenerBeans 集合中
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        // 可以直接获取监听器实例进去,无须在取用的时候再次 getBean getApplicationEventMulticaster().addApplicationListener(this.getBean(listenerBeanName,ApplicationListener.class));
    }
    // 此处先发布早期的监听器集合
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

事件驱动的逻辑执行过程如下:

  • 事件源来发布不同的事件
  • 当发布事件之后会调用多播器的方法来进行事件广播操作,由多播器去触发具体的监听器去执行操作
  • 监听器接收到具体的事件之后,可以验证是否能处理当前事件的类型,如果可以,进行处理;如果不行,不做任何操作

目录
相关文章
|
5天前
|
监控 Java 应用服务中间件
Spring Boot应用的部署与扩展
Spring Boot应用的部署与扩展
|
2天前
|
JSON 监控 Java
Spring Boot中的自定义健康检查
Spring Boot中的自定义健康检查
|
7天前
|
存储 Java Apache
整合Spring Boot和Pulsar实现可扩展的消息处理
整合Spring Boot和Pulsar实现可扩展的消息处理
|
9天前
|
消息中间件 Java Maven
深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter
深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter
|
1天前
|
安全 Java Spring
Spring Boot中的自定义过滤器
Spring Boot中的自定义过滤器
|
3天前
|
Java Maven Spring
Spring Boot中的自定义Starter开发
Spring Boot中的自定义Starter开发
|
3天前
|
监控 Java 应用服务中间件
Spring Boot应用的部署与扩展
Spring Boot应用的部署与扩展
|
7天前
|
Java Maven 开发者
使用Spring Boot创建自定义Starter
使用Spring Boot创建自定义Starter
|
7天前
|
存储 Java Apache
整合Spring Boot和Pulsar实现可扩展的消息处理
整合Spring Boot和Pulsar实现可扩展的消息处理
|
7天前
|
JSON 监控 Java
Spring Boot中的自定义健康检查
Spring Boot中的自定义健康检查