美文网首页
Spring 监听机制

Spring 监听机制

作者: lixwcqs | 来源:发表于2020-05-22 10:15 被阅读0次

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

    JDK其实就有监听模式

    /**
     * @Author lixw
     * @Date 5/22/20 8:59 AM
     */
    public class Producer extends Observable {
        List<Observer> 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<ApplicationListener<?>> 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<ApplicationListener<?>> 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<ApplicationListener<?>> retrieveApplicationListeners(
                ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
    
            List<ApplicationListener<?>> allListeners = new ArrayList<>();
            Set<ApplicationListener<?>> listeners;
            Set<String> 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<ApplicationEvent>, Ordered {}

    public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
        @Override
        public boolean supportsEventType(Class<? extends ApplicationEvent> 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 监听机制

          本文链接:https://www.haomeiwen.com/subject/wvmfahtx.html