相关推荐recommended
Spring的事件监听机制
作者:mmseoamin日期:2024-02-20

这里写自定义目录标题

  • 1. 概述(重点)
  • 2. ApplicationEventMulticaster
    • 2.1 SimpleApplicationEventMulticaster
    • 2.2 AbstractApplicationEventMulticaster
    • 3. ApplicationListener
      • 3.1 注册监听器
      • 3.2 自定义
      • 4. SpringApplicationRunListeners

        1. 概述(重点)

        事件监听机制是观察者模式的一种,Spring的事件监听机制有几个重要的顶层接口,分别是:

        1. ApplicationEventMulticaster 主要看 AbstractApplicationEventMulticaster
        2. ApplicationListener
        3. ApplicationEvent

        它们三哥们的关系可以用下面的图来概括

        Spring的事件监听机制,在这里插入图片描述,第1张

        AbstractApplicationEventMulticaster维护了 源类型和事件类型 作为KEY 跟 监听器的关系,在下面 2.1 SimpleApplicationEventMulticaster有代码的实现解读。

        2. ApplicationEventMulticaster

        目前就只有一个实现类SimpleApplicationEventMulticaster和一个抽象类AbstractApplicationEventMulticaster。

        2.1 SimpleApplicationEventMulticaster

        发布和广播事件,主要注意一下getApplicationListeners方法就行了,会根据事件类型和源类型找监听器。

        @Override
        public void multicastEvent(ApplicationEvent event) {
            multicastEvent(event, resolveDefaultEventType(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);
                }
            }
        }
        

        2.2 AbstractApplicationEventMulticaster

        getApplicationListeners方法就是根据Class、ResolvableType两个对象作为一个缓存key,这个key与一堆监听器`ApplicationListener`做映射,也就是说通过Class、ResolvableType两个对象可以找到监听器,在用法上可以从SimpleApplicationEventMuticaster的 multicastEvent 方法去看。

        看看getApplicationListeners方法的代码实现

        protected Collection> getApplicationListeners(
        	    ApplicationEvent event, ResolvableType eventType) {
            Object source = event.getSource();
            Class sourceType = (source != null ? source.getClass() : null);
            ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
            CachedListenerRetriever newRetriever = null;
            // 这个cacheKey就是ApplicationEvent,ResolvableType两个对象。
            // 根据cacheKey找监听器,找不到就把cacheKey作为key,创建一个什么都么有的CachedListenerRetriever对象作为值缓存到retrieverCache中。
            // 这里有一些细节我没搞明白,putIfAbsent总是返回null。
            CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
            if (existingRetriever == null) {
                if (this.beanClassLoader == null ||
                    (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                    (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
                    newRetriever = new CachedListenerRetriever();
                    existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
                    if (existingRetriever != null) {
                        newRetriever = null;  // no need to populate it in retrieveApplicationListeners
                    }
                }
            }
            if (existingRetriever != null) {
                Collection> result = existingRetriever.getApplicationListeners();
                if (result != null) {
                    return result;
                }
            }
            // 假设上面cacheKey对应的值没有监听器,那这个方面就找 给定事件类型和源类型 的监听器。
            return retrieveApplicationListeners(eventType, sourceType, newRetriever);
        }
        // 从默认的 defaultRetriever 和 我们注入的bean 中找监听器。
        private Collection> retrieveApplicationListeners(
                ResolvableType eventType, @Nullable Class sourceType, @Nullable CachedListenerRetriever retriever) {
            List> allListeners = new ArrayList<>();
            Set> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
            Set filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
            Set> listeners;
            Set listenerBeans;
            synchronized (this.defaultRetriever) {
            listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
            listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
            }
            // 从defaultRetriever中找监听器
            // 这里的supportsEvent有点看不懂,不过只要理解通过事件类型和源类型判断监听器是否符合 事件要求就得了。
            for (ApplicationListener listener : listeners) {
                if (supportsEvent(listener, eventType, sourceType)) {
                    if (retriever != null) {
                        filteredListeners.add(listener);
                    }
                    allListeners.add(listener);
                }
            }
            // 根据bean名字去找监听器
            if (!listenerBeans.isEmpty()) {
                ConfigurableBeanFactory beanFactory = getBeanFactory();
                for (String listenerBeanName : listenerBeans) {
                    try {
                        if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
                            ApplicationListener listener =
                                beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                            if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
                                if (retriever != null) {
                                    if (beanFactory.isSingleton(listenerBeanName)) {
                                        filteredListeners.add(listener);
                                    }
                                    else {
                                        filteredListenerBeans.add(listenerBeanName);
                                    }
                                }
                                allListeners.add(listener);
                            }
                        }
                        else {
                            Object listener = beanFactory.getSingleton(listenerBeanName);
                            if (retriever != null) {
                                filteredListeners.remove(listener);
                            }
                            allListeners.remove(listener);
                        }
                        }
                    catch (NoSuchBeanDefinitionException ex) {
                    }
                }
            }
            // 把找到的监听器都放到CachedListenerRetriever中。
            AnnotationAwareOrderComparator.sort(allListeners);
            if (retriever != null) {
                if (filteredListenerBeans.isEmpty()) {
                    retriever.applicationListeners = new LinkedHashSet<>(allListeners);
                    retriever.applicationListenerBeans = filteredListenerBeans;
                }
                else {
                    retriever.applicationListeners = filteredListeners;
                    retriever.applicationListenerBeans = filteredListenerBeans;
                }
            }
            return allListeners;
        }
        

        3. ApplicationListener

        主要是了解如何注册和自定义监听器就行了

        3.1 注册监听器

        通过META-INF/spring.factories注册监听器。

        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();
            this.bootstrapRegistryInitializers = new ArrayList<>(
                getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
            setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
            // 这里就是注册ApplicationListener的代码了,通过META-INF/spring.factories注册。
            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
            this.mainApplicationClass = deduceMainApplicationClass();
        }
        

        3.2 自定义

        public class MyApplicationPreparedListener implements ApplicationListener {
            @Override
            public void onApplicationEvent(ApplicationPreparedEvent event) {
                System.out.println("开始填充上下文。。。。");
            }
        }
        

        MATE-INF/spring.factories

        org.springframework.context.ApplicationListener=sample.config.MyApplicationPreparedListener
        

        4. SpringApplicationRunListeners

        SpringApplicationRunListeners管理了多个EventPublishingRunListener,EventPublishingRunListener里面包含了事件监听器模型#1.概述(重点)中描述的部分。

        class SpringApplicationRunListeners {
            private final Log log;
            private final List listeners;
            private final ApplicationStartup applicationStartup;
            ...
        }
        public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
            private final SpringApplication application;
            private final String[] args;
            private final SimpleApplicationEventMulticaster initialMulticaster;
            ...
        }
        

        EventPublishingRunListener中定义了Spring整个启动过程中会触发的事件,下面对触发位置进行大概的描述,更具体的内容还有待研究。

        • starting

          在SpringApplication#run,事件ApplicationStartingEvent

        • environmentPrepared

          在SpringApplication#prepareEnvironment,事件ApplicationEnvironmentPreparedEvent

        • contextPrepared

          在SpringApplication#prepareContext,事件ApplicationContextInitializedEvent

        • contextLoaded

          在SpringApplication#prepareContext,事件ApplicationPreparedEvent

        • started

          在SpringApplication#run,事件ApplicationStartedEvent

        • ready

          在SpringApplication#run,事件ApplicationReadyEvent

        • failed

          在SpringApplication#handleRunFailure,事件ApplicationFailedEvent

          我们也可以利用上面的事件,自己创建一个监听器,然后放到spring.factories,比如现在注册一个ApplicationPreparedEvent的监听器。

          public class MyApplicationPreparedListener implements ApplicationListener {
              @Override
              public void onApplicationEvent(ApplicationPreparedEvent event) {
                  System.out.println("开始填充上下文。。。。");
              }
          }
          

          MATE-INF/spring.factories

          org.springframework.context.ApplicationListener=sample.config.MyApplicationPreparedListener