Spring 监听机制

在看一些开源代码的时候,经常出现Spring 发布事件的身影。

JDK其实就有监听模式

/**
 * @Author lixw
 * @Date 5/22/20 8:59 AM
 */
public class Producer extends Observable {
    List listener = new ArrayList<>();
    public Producer() {
        //注册监听者
        listener.add(new Consumer());
    }

    //发布更新 --- 广播消费给注册到Producer的消费者
    public void  publishEvent(){
        System.out.println("生产者有更新,通知消费者");
        Producer producer = this;
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        for (Observer observer : listener) {
            observer.update(producer, LocalDateTime.now().format(formatter) + "发送新的消息");
        }
    }

    public static void main(String[] args) {
        new Producer().publishEvent();
    }

    //定义消费者 也就是监听者
    class Consumer implements Observer {
        //定义接收到消息的逻辑
        @Override
        public void update(Observable o, Object arg) {
            System.out.println("消费者接受到" + o + "的消息:" + arg);
        }
    }
}
  1. 事件的发布者继承Observable
  2. 事件的监听者实现Observer,
  3. 定义监听列表,讲监听者注册到发布者列表中
  4. 发布事件的时候,通过监听者列表进行广播
  5. 监听者在update中实现监听逻辑

可以看到第三步是建立事件发布者和监听者联系的核心

那么Spring的具体实现呢?结合Spring Boot的自动配置文件加载机制来看看

image.png

事件发布者: ApplicationEnvironmentPreparedEvent

类似 JDK的Observable

监听者: ConfigFileApplicationListener

类似 JDK的Observer

查看ApplicationEnvironmentPreparedEvent的源码并没有发现的实现有地方可以注册监听者或者存储监听者
那么两者是如何建立联系的?通过Debug的栈帧,可以看到


image.png

line134: 求出了event(ApplicationEnvironmentPreparedEvent)的所有的监听者,line139通过Debug信息可以看到listener就是ConfigFileApplicationListener

继续看AbstractApplicationEventMulticaster.getApplicationListeners源码

    /**
     * Return a Collection of ApplicationListeners matching the given
     * event type. Non-matching listeners get excluded early.
     * @param event the event to be propagated. Allows for excluding
     * non-matching listeners early, based on cached matching information.
     * @param eventType the event type
     * @return a Collection of ApplicationListeners
     * @see org.springframework.context.ApplicationListener
     */
    protected Collection> getApplicationListeners(
            ApplicationEvent event, ResolvableType eventType) {

        Object source = event.getSource();
        Class sourceType = (source != null ? source.getClass() : null);
        ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
//走缓存
        // Quick check for existing entry on ConcurrentHashMap...
        ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
        if (retriever != null) {
            return retriever.getApplicationListeners();
        }

        if (this.beanClassLoader == null ||
                (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                        (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
            // Fully synchronized building and caching of a ListenerRetriever
            synchronized (this.retrievalMutex) {
                retriever = this.retrieverCache.get(cacheKey);
                if (retriever != null) {
                    return retriever.getApplicationListeners();
                }
                retriever = new ListenerRetriever(true);
               // 求监听者列表
                Collection> listeners =
                        retrieveApplicationListeners(eventType, sourceType, retriever);
                //缓存
                this.retrieverCache.put(cacheKey, retriever);
                return listeners;
            }
        }
        else {
            // No ListenerRetriever caching -> no synchronization necessary
            return retrieveApplicationListeners(eventType, sourceType, null);
        }
    }
    /**
     * Actually retrieve the application listeners for the given event and source type.
     * @param eventType the event type
     * @param sourceType the event source type
     * @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)
     * @return the pre-filtered list of application listeners for the given event and source type
     */
    private Collection> retrieveApplicationListeners(
            ResolvableType eventType, @Nullable Class sourceType, @Nullable ListenerRetriever retriever) {

        List> allListeners = new ArrayList<>();
        Set> listeners;
        Set listenerBeans;
        synchronized (this.retrievalMutex) {
            listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
            listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
        }

        // Add programmatically registered listeners, including ones coming
        // from ApplicationListenerDetector (singleton beans and inner beans).
        for (ApplicationListener listener : listeners) {
//事件和监听者建立联系
            if (supportsEvent(listener, eventType, sourceType)) {
                if (retriever != null) {
                    retriever.applicationListeners.add(listener);
                }
                allListeners.add(listener);
            }
        }
                ...
        return allListeners;
    }

supportsEvent的实现


image.png

继续看ConfigFileApplicationListener实现了SmartApplicationListener

public interface SmartApplicationListener extends ApplicationListener, Ordered {}

public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
    @Override
    public boolean supportsEventType(Class eventType) {
        return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
                || ApplicationPreparedEvent.class.isAssignableFrom(eventType);
    }
}

listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);

可以知道的defaultRetriever中存储了监听者列表是怎么加载的呢?

  1. 现在SpringApplication的源码(new SpringApplication()的时候执行)
    public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
          //加载了监听器
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

Spring Boot 初始化的时候EventPublishingRunListener的时候会执行

    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
       //从SpringApplication拿到监听者列表
        for (ApplicationListener listener : application.getListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
        }
    }

SimpleApplicationEventMulticaster(AbstractApplicationEventMulticaster)的代码

@Override
    public void addApplicationListener(ApplicationListener listener) {
        synchronized (this.retrievalMutex) {
            // Explicitly remove target for a proxy, if registered already,
            // in order to avoid double invocations of the same listener.
            Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
            if (singletonTarget instanceof ApplicationListener) {
                this.defaultRetriever.applicationListeners.remove(singletonTarget);
            }
           //讲监听器添加到defaultRetriever中
            this.defaultRetriever.applicationListeners.add(listener);
            this.retrieverCache.clear();
        }
    }

到这,ApplicationListener是什么时候在那生成,存储在那,如何和event关联就只全部知道了。总结

  1. SpringApplication有一个ApplicationListener监听者列表,实例化的时候,Spring会ApplicationListener类型通过JDK发射机制生成,保存到SpringApplication的 listeners 列表中
  2. Spring容器初始化到EventPublishingRunListener的时候,会SpringApplication保存的ApplicationListener实例保存到SimpleApplicationEventMulticaster对象的defaultRetriever对象中
  3. SpringApplication执行run方法的时候,会生成一个SpringApplicationRunListeners对象
    ,并且在run方法中,会出发配置环境初始化的工作,并生成ApplicationEnvironmentPreparedEvent事件对象
    SpringApplicationRunListeners listeners = getRunListeners(args);
    ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
    --> listeners.environmentPrepared(environment);
    --> listener.environmentPrepared(environment);
    --> this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
    4.SpringBoot 通过广播机制,发布事件。在SimpleApplicationEventMulticaster并通过ApplicationEvent event和ResolvableType eventType过滤筛选出监听event事件的监听者,触发监听者方法
  @Override
  public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
      ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
      Executor executor = getTaskExecutor();
      for (ApplicationListener listener : getApplicationListeners(event, type)) {
          if (executor != null) {
              executor.execute(() -> invokeListener(listener, event));
          }
          else {
              invokeListener(listener, event);
          }
      }
  }

SimpleApplicationEventMulticaster 是个广播者,其拥有全部的SpringListener实例,然后发布事件的时候调用multicastEvent方法,通过方法列表参数过滤出符合条件的了监听者,监听者触发监听逻辑。

你可能感兴趣的:(Spring 监听机制)