【spring原始碼學習】spring的事件釋出監聽機制原始碼解析

Love Lenka發表於2017-07-26

【一】相關原始碼類

(1)spring的事件釋出監聽機制的核心管理類:org.springframework.context.event.SimpleApplicationEventMulticaster.

  =>該類的初始化是放在專案載入時,在ioc容器xml配置檔案解析載入完畢後,註冊bean建立前後置處理實現類(BeanPostProcessor 介面實現),beanFactory配置處理(BeanFactoryPostProcessor介面實現)後,初始化該事件釋出監聽機制的核心類。

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // 解析xml配置檔案
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // 註冊未來bean例項化的前後置處理的PostProcessor介面實現
                postProcessBeanFactory(beanFactory);

                //執行所有實現BeanFactoryPostProcessor介面實現,對beanFactory進行處理
                invokeBeanFactoryPostProcessors(beanFactory);

                //  註冊未來bean例項化的前後置處理的PostProcessor介面實現
                registerBeanPostProcessors(beanFactory);

                // 註冊未來bean例項化的前後置處理的PostProcessor介面實現
                initMessageSource();

                // 例項化spring事件釋出監聽機制的核心類,SimpleApplicationEventMulticaster
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // 註冊事件監聽器
                registerListeners();

                // 例項化非懶載入的bean,完成ioc容器中bean的例項化和反轉依賴,並在內部實現動態代理相關的操作
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }
        }
    }
View Code

 

(2)spring的事件釋出監聽機制的監聽器類的介面:org.springframework.context.ApplicationListener<E extends ApplicationEvent>

  =>監聽器的定義必須實現該介面。

  =>所監聽的事件也必須繼承org.springframework.context.ApplicationEvent的抽象類

  =>在初始化管理類後,會註冊監聽器。會從beanFactory裡得到所有實現ApplicationListener介面的bean的名字,並註冊到ListenerRetriever的屬性applicationListenerBeans集合中。

 

(3)spring的事件釋出監聽機制的事件的基礎類:org.springframework.context.ApplicationEvent

  =>事件的事件類必須繼承該基類

  =>定義監聽器的同時,必須定義相關的事件類。

 

(4)spring的事件釋出監聽機制的儲存事件監聽的類:org.springframework.context.event.AbstractApplicationEventMulticaster.ListenerRetriever

    =>該類內部儲存了一個n個事件對應的多個監聽器

    =>屬性Set<ApplicationListener<?>> applicationListeners  儲存的是事件監聽器的例項

    =>屬性Set<String> applicationListenerBeans  儲存的事件監聽器在ioc容器中的beanNames



(5)spring的事件釋出監聽機制的儲存事件體的類:org.springframework.context.event.AbstractApplicationEventMulticaster.ListenerCacheKey

    =>一個事件體的class型別+事件源(事件體記憶體儲的資料)的class型別決定由那些監聽監聽器處理該事件

    =>屬性Class<?> eventType 儲存的事件體的class型別

    =>屬性Class<?> sourceType 儲存的事件源的class型別(事件體內資料)

 

【二】設計思想

(1)透過事件體,拿到事件類的cls1型別,和事件源(事件體內部儲存的資料類)的cls型別

(2)然後在IOC容器中所有實現ApplicationListener介面的事件監聽器中進行匹配。找到所有適合該事件的事件監聽器集合。將事件監聽集合形成ListenerRetriever物件。

  =>從IOC容器中的一個個事件監聽器實現類的範型填充類的型別(也就是事件體的 型別)cls2

  =>Listener可能是代理物件(因為@Async註解),Listenner的ioc在例項化階段,會被spring建立成代理物件。spring內部也會做處理,得到代理物件代理的targetClass,也就是Listenner的真實型別。

  =>看當前事件體的型別cls1是否是事件監聽器的範型填充類的型別cls2的子類或本身。如果是,則表示這個事件監聽器匹配該事件。

(3)將該事件體,的事件類的cls1型別+事件源的cls型別。形成ListenerCacheKey物件,以此為key,以事件監聽集合ListenerRetriever物件作為value,儲存在AbstractApplicationEventMulticaster類中private final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>(64);屬性中作為cache,方便下次匹配,不再從ioc容器中重新匹配。

 

【三】事件緩衝,擴充套件。hasMap中以物件作為key。需要重寫hasCode方法,equals方法

private static class ListenerCacheKey {

        private final Class<?> eventType;

        private final Class<?> sourceType;

        public ListenerCacheKey(Class<?> eventType, Class<?> sourceType) {
            this.eventType = eventType;
            this.sourceType = sourceType;
        }

        @Override
        public boolean equals(Object other) {
            if (this == other) {
                return true;
            }
            ListenerCacheKey otherKey = (ListenerCacheKey) other;
            return ObjectUtils.nullSafeEquals(this.eventType, otherKey.eventType) &&
                    ObjectUtils.nullSafeEquals(this.sourceType, otherKey.sourceType);
        }

        @Override
        public int hashCode() {
            return ObjectUtils.nullSafeHashCode(this.eventType) * 29 + ObjectUtils.nullSafeHashCode(this.sourceType);
        }
    }
View Code

 

相關文章