Spring容器的基本實現之源碼分析-下篇

​ 本文接着上一篇 《Spring容器的基本實現之源碼分析-上篇》 接着來繼續分析 Spring容器啓動流程。

​ 本篇將會討論 Spring 啓動流程中剩下的幾個核心方法, 包括 BeanFactory 後處理、初始化非延遲加載單例、finishRefresh這幾個方法的具體流程。

下篇目錄:


2438927-ab20f4d516cabbd3.png
下篇目錄.png

BeanFactory 的後處理

BeanFactory 作爲 Spring 中容器功能的基礎,用於存放所有已加載的 bean ,爲了保證程序的高度可擴展, Spring 針對 BeanFactory 做了大量的擴展,比如我們熟知的 PostProcessor 等都是在這裏實現的。

激活註冊的BeanFactoryPostProcessor

​ 首先我們先了解下BeanFactoryPostProcessor的用法。簡單來說 BeanFactoryPostProcessor 和前面說的BeanPostProcessor類似,可以對bean的定義(配置元數據) 進行處理。那麼它們之前的區別是什麼呢?

簡單來說,SpringIOC 允許BeanFactoryPostProcessor 在容器實際實例化任何其他的bean之前讀取配置的元數據,它的作用於是容器級的,如果是想改變實際的bean實例,那麼最好還是使用 BeanPostProcessor 。在 Spring中存在對於 BeanFactoryPostProcessor 的典型應用,比如 PropertyPlaceholderConfigurer。

  1. BeanFactoryPostProcessor 的典型應用: PropertyPlaceholderConfigurer

    我們在配置Spring的Bean描述文件時,經常會使用屬性變量引用:

        <bean id="helloMessage" class="com.ccgogoing.domain.HelloMessage">
            <property name="meg" value="${bean.message}"/>
        </bean>
    

    這種使用變量的方式,就是Spring的分散配置,可以在另外的配置文件中爲 bean.message 指定值。如在 bean.properties 文件中指定:

    bean.message=Hello World!
    

    當訪問bean時,其屬性就會被置爲配置的字符串,但問題是Spring怎樣知道存在這樣的配置文件呢? 這就要靠 PropertyPlaceholderConfigurer 這個類的bean:

        <bean id="msgHandler" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="locations">
                <list>
                    <value>config/bean.properties</value>
                </list>
            </property>
        </bean>
    

在這個bean中指定了配置文件爲 config/bean.properties ,這裏我們似乎明白了,但仔細想一下,這個"msgHandler" 只是配置爲Spring管理的一個 Bean,並沒有被別的bean或者對象引用,Spring 的 BeanFactory 怎樣知道要從這個 bean中獲取配置信息呢?

​ 查看 PropertyPlaceholderConfigurer 的層次結構,可以看到這個類間接繼承了 BeanFactoryPostProcessor 接口。這是一個很特別的接口,當Spring加載任何實現了這個接口的bean的配置時,都會在 bean 工廠載入所有bean 的配置之後執行 postProcessorBeanFactory 方法。在 PropertyResourceConfigurer 類中實現了postProcessorBeanFactory 方法,在方法中先後調用了 mergeProperties、 convertProperties、 processProperties這三個方法,分別得到配置,將得到的配置轉換爲合適的類型,最後將配置的內容告知BeanFactory。

2438927-5f030fee12f62bc4.jpg
PlaceholderConfigurerSupport層級.jpg
@Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        try {
            Properties mergedProps = mergeProperties();

            // Convert the merged properties, if necessary.
            convertProperties(mergedProps);

            // Let the subclass process the properties.
            processProperties(beanFactory, mergedProps);
        }
        catch (IOException ex) {
            throw new BeanInitializationException("Could not load properties", ex);
        }
    }

​ 正是通過實現 BeanFactoryPostProcessor 接口, BeanFactory 會在實例化任何 bean 之前獲得配置信息,從而能夠正確解析 bean 描述文件中的變量引用。

  1. 使用自定義的 BeanFactoryPostProcessor

    我們實現一個 BeanFactoryPostProcessor ,去除潛在的‘流氓’屬性值來展示自定義 BeanFactoryPostProcessor 的創建和使用,例如在 bean 定義中留下 bollocks 這樣的字眼。

    配置文件 beans.xml

    <bean id="bfpp" class="com.ccgogoing.domain.ObScenityRemovingBeanFactoryPostProcessor">
        <property name="obscenties">
            <set>
                <value>bollocks</value>
                <value>winky</value>
                <value>bum</value>
                <value>MicroSoft</value>
            </set>
        </property>
    </bean>

    <bean id="simple" class="com.ccgogoing.domain.SimplePostProcessor">
        <property name="password" value="bollocks"/>
        <property name="username" value="imaginecup"/>
        <property name="connectString" value="MicroSoft"/>
    </bean>

ObScenityRemovingBeanFactoryPostProcessor.java

public class ObScenityRemovingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    private Set<String> obscenties;

    public ObScenityRemovingBeanFactoryPostProcessor() {
        this.obscenties = new HashSet<>();
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String [] beanNames = beanFactory.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            StringValueResolver stringValueResolver = strVal -> {
                if (isObscene(strVal)) {
                    return "*****";
                }
                return strVal;
            };
            BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(stringValueResolver);
            visitor.visitBeanDefinition(beanDefinition);
        }
    }

    public boolean isObscene (Object val) {
        String potentialObscenity = val.toString().toUpperCase();
        return this.obscenties.contains(potentialObscenity);
    }

    public void setObscenties(Set<String> obscenties) {
        this.obscenties.clear();
        for (String obscenity : obscenties) {
            this.obscenties.add(obscenity.toUpperCase());
        }
    }
}

測試類

    @Test
    public void testObscenityPostProcessor() {
        ConfigurableListableBeanFactory bf = new XmlBeanFactory(new ClassPathResource("beans.xml"));
        BeanFactoryPostProcessor beanFactoryPostProcessor = (BeanFactoryPostProcessor) bf.getBean("bfpp");
        beanFactoryPostProcessor.postProcessBeanFactory(bf);
        System.out.println(bf.getBean("simple"));
    }

輸出結果

SimplePostProcessor{connectString='*****', password='*****', username='imaginecup'}

通過自定義的 BeanFactoryPostProcessor Spring 很好的實現了屏蔽掉 obscenties 定義的不應該展示的屬性。

  1. 激活 BeanFactoryPostProcessor

    上面瞭解了 BeanFactoryPostProcessor 的用法之後我們在深入研究其調用過程。

public static void invokeBeanFactoryPostProcessors(
         ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

     // Invoke BeanDefinitionRegistryPostProcessors first, if any.
     Set<String> processedBeans = new HashSet<String>();
         // 對 BeanDefinitionRegistry 類型的處理
     if (beanFactory instanceof BeanDefinitionRegistry) {
         BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
         List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
         List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>();
         // 硬編碼註冊的後處理器
         for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
             if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                 BeanDefinitionRegistryPostProcessor registryProcessor =
                         (BeanDefinitionRegistryPostProcessor) postProcessor;
                      // 對於BeanDefinitionRegistryPostProcessor類型的,在BeanFactoryPostProcessor的基礎上還有自己定義的方法,需要先調用
                 registryProcessor.postProcessBeanDefinitionRegistry(registry);
                 registryProcessors.add(registryProcessor);
             }
             else {
                      // 記錄常規的BeanFactoryPostProcessor
                 regularPostProcessors.add(postProcessor);
             }
         }

         // Do not initialize FactoryBeans here: We need to leave all regular beans
         // uninitialized to let the bean factory post-processors apply to them!
         // Separate between BeanDefinitionRegistryPostProcessors that implement
         // PriorityOrdered, Ordered, and the rest.
         List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();

         // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
             // 配置註冊的後置處理器
         String[] postProcessorNames =
                 beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
         for (String ppName : postProcessorNames) {
                  // 先調用實現了PriorityOrdered 接口的
             if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                 processedBeans.add(ppName);
             }
         }
         sortPostProcessors(currentRegistryProcessors, beanFactory);
         registryProcessors.addAll(currentRegistryProcessors);
             // BeanDefinitionRegistryPostProcessor的特殊處理
         invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
         currentRegistryProcessors.clear();

         // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
         postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
         for (String ppName : postProcessorNames) {
                  // 接下來調用 實現了Ordered 接口的
             if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                 processedBeans.add(ppName);
             }
         }
         sortPostProcessors(currentRegistryProcessors, beanFactory);
         registryProcessors.addAll(currentRegistryProcessors);
         invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
         currentRegistryProcessors.clear();

         // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
         boolean reiterate = true;
         while (reiterate) {
             reiterate = false;
             postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
             for (String ppName : postProcessorNames) {
                      // 處理剩餘的BeanDefinitionRegistryPostProcessors,直到沒有
                 if (!processedBeans.contains(ppName)) {
                     currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                     processedBeans.add(ppName);
                     reiterate = true;
                 }
             }
             sortPostProcessors(currentRegistryProcessors, beanFactory);
             registryProcessors.addAll(currentRegistryProcessors);
             invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
             currentRegistryProcessors.clear();
         }

         // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
             // 激活BeanDefinitionRegistryPostProcessor的postProcessBeanFactory,之前激活的是postProcessBeanDefinitionRegistry
         invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
             // 激活硬編碼註冊的常規postProcessors
         invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
     }

     else {
         // Invoke factory processors registered with the context instance.
             // bean工廠非BeanDefinitionRegistry,激活硬編碼的beanFactoryPostProcessors
         invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
     }

     // Do not initialize FactoryBeans here: We need to leave all regular beans
     // uninitialized to let the bean factory post-processors apply to them!
         // 對於配置中讀取的BeanFactoryPostProcessor的處理
     String[] postProcessorNames =
             beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

     // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
     // Ordered, and the rest.
     List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
     List<String> orderedPostProcessorNames = new ArrayList<String>();
     List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
      // 對後置處理器進行分類
     for (String ppName : postProcessorNames) {
         if (processedBeans.contains(ppName)) {
             // skip - already processed in first phase above 上面第一步已經處理
         }
         else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
             priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
         }
         else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
             orderedPostProcessorNames.add(ppName);
         }
         else {
             nonOrderedPostProcessorNames.add(ppName);
         }
     }

     // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
         // 對於實現PriorityOrdered接口的 按照優先級進行排序
     sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
     invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

     // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
         // 按照order進行排序
     List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
     for (String postProcessorName : orderedPostProcessorNames) {
         orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
     }
     sortPostProcessors(orderedPostProcessors, beanFactory);
     invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

     // Finally, invoke all other BeanFactoryPostProcessors.
     List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
     for (String postProcessorName : nonOrderedPostProcessorNames) {
         nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
     }
         // 無序,直接調用
     invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

     // Clear cached merged bean definitions since the post-processors might have
     // modified the original metadata, e.g. replacing placeholders in values...
     beanFactory.clearMetadataCache();
 }

從上面的方法中我們發現,對於 BeanFactoryPostProcessor 的處理分爲兩種情況進行:

一種是 ConfigurableListableBeanFactory 屬於 BeanDefinitionRegistry ,則需要處理 BeanDefinitionRegistryPostProcessor,另外一種是 beanFactory 不屬於 BeanDefinitionRegistry 則只需要處理 BeanFactoryPostProcessor。而對於這兩種情況 則都需要考慮硬編碼註冊的後置處理器以及通過配置註冊的後置處理器。

這裏我們一起看下 BeanDefinitionRegistry 類型的處理過程,因爲非BeanDefinitionRegistry 類型的只需要進行普通BeanFactoryPostProcessor 的處理。

(1)對於硬編碼註冊的後置處理器,主要是通過 AbstractApplicationContext 中添加後置處理器的方法 addBeanFactoryPostProcessor 進行添加:

 public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
     Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
     this.beanFactoryPostProcessors.add(postProcessor);
 }

添加的後處理器被放在beanFactoryPostProcessors 中,而在調用處理 BeanFactoryPostProcessor 時會判斷beanFactoryPostProcessors 是否有數據。由於 BeanDefinitionRegistryPostProcessor 繼承自 BeanFactoryPostProcessor ,因此它不但有 BeanFactoryPostProcessor 的特性同時還有自定義的個性化方法,所以這裏需要從beanFactoryPostProcessors 中過濾出BeanDefinitionRegistryPostProcessor 類型的後處理器,進行其個性化方法 postProcessBeanDefinitionRegistry 的調用。

(2)記錄後處理器使用了兩個List。 registryProcessors 記錄 BeanDefinitionRegistryPostProcessor 這種特殊的後處理器,regularPostProcessors 記錄通過硬編碼註冊的BeanFactoryPostProcessor 類型的處理器。

(3) 將通過配置註冊的 BeanDefinitionRegistryPostProcessor 按照優先級排序並調用postProcessBeanDefinitionRegistry 然後加入到registryProcessors 這個List中。對於這兩個List進行統一的調用 BeanFactoryPostProcessor 類的 postProcessBeanFactory方法。

(4) 通過配置註冊的普通BeanFactoryPostProcessor 處理。和BeanDefinitionRegistryPostProcessor 處理流程類似。

BeanDefinitionRegistryPostProcessor 只對 BeanDefinitionRegistry 類型的beanFactory有效,所以如果 beanFactory 並不是 BeanDefinitionRegistry 類型,則只需要處理 BeanFactoryPostProcessor ,包括硬編碼註冊和配置註冊的後處理器。

認真看的同學會發現,對於硬編碼方法註冊的 BeanFactoryPostProcessor 不需要作任何排序,但是在配置文件中讀取的處理器,Spring並不會保證讀取的順序。所以爲了保證用戶的調用順序的要求,Spring對於後處理器的調用支持按照PriorityOrdered 或者Ordered的調用順序。

註冊BeanPostProcessor

​ 上面我們提到了 BeanFactoryPostProcessor 的調用,這一節我們學習 BeanPostProcessor ,但是這裏並不是調用而是註冊。真正的調用其實是在 bean 的實例化階段。這是一個很重要的步驟,由於不調用後處理器導致很多功能 BeanFactory 不支持。

​ 下面我們繼續探討 registerBeanPostProcessors 的方法實現。

public static void registerBeanPostProcessors(
            ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

        // Register BeanPostProcessorChecker that logs an info message when
        // a bean is created during BeanPostProcessor instantiation, i.e. when
        // a bean is not eligible for getting processed by all BeanPostProcessors.
        int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
        beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

        // Separate between BeanPostProcessors that implement PriorityOrdered,
        // Ordered, and the rest.
        List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
        List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
        List<String> orderedPostProcessorNames = new ArrayList<String>();
        List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
                priorityOrderedPostProcessors.add(pp);
                if (pp instanceof MergedBeanDefinitionPostProcessor) {
                    internalPostProcessors.add(pp);
                }
            }
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            }
            else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }

        // First, register the BeanPostProcessors that implement PriorityOrdered.
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

        // Next, register the BeanPostProcessors that implement Ordered.
        List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
        for (String ppName : orderedPostProcessorNames) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            orderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        sortPostProcessors(orderedPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, orderedPostProcessors);

        // Now, register all regular BeanPostProcessors.
        List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
        for (String ppName : nonOrderedPostProcessorNames) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            nonOrderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

        // Finally, re-register all internal BeanPostProcessors.
        sortPostProcessors(internalPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, internalPostProcessors);

        // Re-register post-processor for detecting inner beans as ApplicationListeners,
        // moving it to the end of the processor chain (for picking up proxies etc).
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
    }

BeanFactoryPostProcessor 和 BeanPostProcessor 兩者之間區別不大,感興趣的可以再看下上面代碼,相信不難看懂。

初始化消息資源

這裏主要進行國際化處理,即常見的多語言app,需要按照客戶端的語言返回不同的頁面 。 Spring 定義了訪問國際化信息的 MessageSource 接口,並提供了幾個易用的實現類。 Message 接口分別被 HierarchicalMessageSource 和ApplicationContext 接口擴展。

    protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
            this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
            // Make MessageSource aware of parent MessageSource.
            if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
                HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
                if (hms.getParentMessageSource() == null) {
                    // Only set parent context as parent MessageSource if no parent MessageSource
                    // registered already.
                    hms.setParentMessageSource(getInternalParentMessageSource());
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Using MessageSource [" + this.messageSource + "]");
            }
        }
        else {
            // Use empty MessageSource to be able to accept getMessage calls.
            DelegatingMessageSource dms = new DelegatingMessageSource();
            dms.setParentMessageSource(getInternalParentMessageSource());
            this.messageSource = dms;
            beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
                        "': using default [" + this.messageSource + "]");
            }
        }
    }

初始化ApplicationEventMulticaster

​ 在開始研究 Spring 的時間傳播器之前,我們先來看一個 Spring 的事件監聽的簡單用法。

  1. 定義監聽事件。

    public class TestEvent extends ApplicationEvent{
    
        public String msg;
    
        /**
         * Create a new ApplicationEvent.
         *
         * @param source the object on which the event initially occurred (never {@code null})
         */
        public TestEvent(Object source) {
            super(source);
        }
    
        public TestEvent(Object source,String msg) {
            super(source);
            this.msg = msg;
        }
    
        public void print() {
            System.out.println(msg);
        }
    }
    
  1. 定義監聽器

    public class TestListener implements ApplicationListener{
    
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            if (event instanceof TestEvent) {
                TestEvent testEvent = (TestEvent) event;
                testEvent.print();
            }
        }
    }
    
  2. 添加配置文件

    <bean id="testListener" class="com.ccgogoing.listener.TestListener"/>
    
  1. 測試

        @Test
        public void testEvent() {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
            TestEvent testEvent = new TestEvent("hello","msg");
            applicationContext.publishEvent(testEvent);
        }
    

當程序運行時,Spring 會將發出的 TestEvent 事件轉給我自定義的 TestLinstener 進行進一步處理。

相信很多人看到這裏,一下子會想到了觀察者模式,這確實是個典型的應用,可以在比較關心的事件結束後及時進行處理。那麼我們接下來一起看看 ApplicationEventMulticaster 是如何被初始化的,以確保功能的正確運行。

initApplicationEventMulticaster 的方式比較簡單,無非考慮兩種情況。

  • 如果用戶自定義了事件廣播器則使用自定義的廣播器。
  • 如果用戶沒有自定義的事件廣播器,則使用默認的 ApplicationEventMulticaster。
protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            if (logger.isDebugEnabled()) {
                logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                        APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                        "': using default [" + this.applicationEventMulticaster + "]");
            }
        }
    }

按照之前我們瞭解的事件監聽的順序和邏輯,我們推斷,作爲廣播器,一定是用於存放監聽器並在合適的時候調用監聽器,那麼我們不妨進入默認的廣播器實現 SimpleApplicationEventMulticaster 來一探究竟。

下面這段代碼是關鍵所在:

    @Override
    public void multicastEvent(ApplicationEvent event) {
        multicastEvent(event, resolveDefaultEventType(event));
    }

    @Override
    public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        invokeListener(listener, event);
                    }
                });
            }
            else {
                invokeListener(listener, event);
            }
        }
    }

可以看到,當產生Spring 事件的時候會默認使用 SimpleApplicationEventMulticaster 的 multicastEvent 方法來廣播事件,遍歷所有監聽器,並使用監聽器中的 onApplicationEvent 方法來進行監聽器處理。

註冊監聽器

​ 上面在學習 Spring 廣播器的時候反覆提到了事件監聽器,那麼在 Spring註冊監聽器的時候又做了哪些邏輯操作呢?

protected void registerListeners() {
        // Register statically specified listeners first.
         // 硬編碼方式註冊的監聽器處理
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let post-processors apply to them!
        // 配置文件註冊的監聽器處理
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // Publish early application events now that we finally have a multicaster...
        // 由於上一步初始化了廣播器,那麼就開始派發早期的事件吧
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }

初始化非延遲加載單例

​ 完成 BeanFactory 的初始化工作,其中包括 ConversionService 的設置、配置凍結 以及 非延遲加載的 bean 的初始化工作。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // Initialize conversion service for this context.
        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
                beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
            beanFactory.setConversionService(
                    beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
        }

        // Register a default embedded value resolver if no bean post-processor
        // (such as a PropertyPlaceholderConfigurer bean) registered any before:
        // at this point, primarily for resolution in annotation attribute values.
        if (!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
                @Override
                public String resolveStringValue(String strVal) {
                    return getEnvironment().resolvePlaceholders(strVal);
                }
            });
        }

        // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        for (String weaverAwareName : weaverAwareNames) {
            getBean(weaverAwareName);
        }

        // Stop using the temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(null);

        // Allow for caching all bean definition metadata, not expecting further changes.
        // 凍結所有 bean 定義,說明註冊的bean定義將不被修改或任何進一步的處理
        beanFactory.freezeConfiguration();

        // Instantiate all remaining (non-lazy-init) singletons.
        // 初始化剩下的所有非延遲加載的單實例bean
        beanFactory.preInstantiateSingletons();
    }

  1. ConversionService 的設置

    Spring提供了一種類型轉換方式:使用converter,比如將String 轉換爲 Date。下面我們使用一個簡單的示例來了解下 Converter 的使用方式。

    (1) 定義轉換器

    public class String2DateConverter implements Converter<String,Date> {
        @Override
        public Date convert(String source) {
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                Date date = sdf.parse(source);
                return date;
            } catch (Exception e) {
                return null;
            }
        }
    }
    

    (2) 註冊

        <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
            <property name="converters">
                <list>
                    <bean class="com.ccgogoing.domain.String2DateConverter"/>
                </list>
            </property>
        </bean>
    

    (3) 測試

         @Test
        public void testString2DateConvert() {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
            DefaultConversionService conversionService = (DefaultConversionService) applicationContext.getBean("conversionService");
            conversionService.addConverter(new String2DateConverter());
            String dateStr = "2019-02-21";
            Date date = conversionService.convert(dateStr,Date.class);
            System.out.println(date);
        }
    
    

    通過以上功能我們看到了 Converter 和 ConversionService 提供的便利功能,其中的配置就是在當前函數中初始化的。

  1. 凍結配置

    凍結所有bean的定義,說明註冊的bean定義將不再做任何修改或進行任何一進步的處理。

     @Override
     public void freezeConfiguration() {
         this.configurationFrozen = true;
         this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
     }
    
  1. 初始化非延遲加載

    ApplicationContext 實現的默認行爲就是在啓動時將所有的單例 bean 提前實例化。 提前實例化意味着作爲初始化過程的一部分, ApplicationContext 實例會創建並配置所有的單例 bean。通常情況下這是一件好事,因爲這樣在配置中的任何錯誤就會被即刻發現(否則可能要花幾個小時甚至幾天)。 而這個實例化的過程就是在 preInstantiateSingletons 中完成的。

    @Override
     public void preInstantiateSingletons() throws BeansException {
         if (this.logger.isDebugEnabled()) {
             this.logger.debug("Pre-instantiating singletons in " + this);
         }
    
         // Iterate over a copy to allow for init methods which in turn register new bean definitions.
         // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
         List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
    
         // Trigger initialization of all non-lazy singleton beans...
         for (String beanName : beanNames) {
             RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
             if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                 if (isFactoryBean(beanName)) {
                     final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                     boolean isEagerInit;
                     if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                         isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                             @Override
                             public Boolean run() {
                                 return ((SmartFactoryBean<?>) factory).isEagerInit();
                             }
                         }, getAccessControlContext());
                     }
                     else {
                         isEagerInit = (factory instanceof SmartFactoryBean &&
                                 ((SmartFactoryBean<?>) factory).isEagerInit());
                     }
                     if (isEagerInit) {
                         getBean(beanName);
                     }
                 }
                 else {
                     getBean(beanName);
                 }
             }
         }
    
         // Trigger post-initialization callback for all applicable beans...
         for (String beanName : beanNames) {
             Object singletonInstance = getSingleton(beanName);
             if (singletonInstance instanceof SmartInitializingSingleton) {
                 final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                 if (System.getSecurityManager() != null) {
                     AccessController.doPrivileged(new PrivilegedAction<Object>() {
                         @Override
                         public Object run() {
                             smartSingleton.afterSingletonsInstantiated();
                             return null;
                         }
                     }, getAccessControlContext());
                 }
                 else {
                     smartSingleton.afterSingletonsInstantiated();
                 }
             }
         }
     }
    

finishRefresh

​ 在 Spring 中提供了 LifeCycle 接口, LifeCycle 中包含start/stop 方法,實現此接口後Spring 會保證在啓動的時候調用 start 方法開始生命週期,並在 Spring 關閉的時候調用 stop 方法來結束生命週期,通常用來配置後臺程序,再啓動後一直運行(如對MQ進行輪詢等)。而 ApplicationContext 的初始化最後正是保證了這一功能的實現。

    protected void finishRefresh() {
        // Initialize lifecycle processor for this context.
        initLifecycleProcessor();

        // Propagate refresh to lifecycle processor first.
        getLifecycleProcessor().onRefresh();

        // Publish the final event.
        publishEvent(new ContextRefreshedEvent(this));

        // Participate in LiveBeansView MBean, if active.
        LiveBeansView.registerApplicationContext(this);
    }
  1. initLifecycleProcessor

    當ApplicationContext 啓動或停止時,它會通過LifeCycleProcessor來與所有生命的 bean 的週期做狀態更新,而在LifeCycleProcessor 的使用前首先需要進行初始化。

protected void initLifecycleProcessor() {
     ConfigurableListableBeanFactory beanFactory = getBeanFactory();
     if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
         this.lifecycleProcessor =
                 beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
         if (logger.isDebugEnabled()) {
             logger.debug("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
         }
     }
     else {
         DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
         defaultProcessor.setBeanFactory(beanFactory);
         this.lifecycleProcessor = defaultProcessor;
         beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
         if (logger.isDebugEnabled()) {
             logger.debug("Unable to locate LifecycleProcessor with name '" +
                     LIFECYCLE_PROCESSOR_BEAN_NAME +
                     "': using default [" + this.lifecycleProcessor + "]");
         }
     }
 }
  1. OnRefresh

    啓動所有實現了 LifeCycle 接口的 bean。

 @Override
 public void onRefresh() {
     startBeans(true);
     this.running = true;
 }
 
 
 private void startBeans(boolean autoStartupOnly) {
     Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
     Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
     for (Map.Entry<String, ? extends Lifecycle> entry : lifecycleBeans.entrySet()) {
         Lifecycle bean = entry.getValue();
         if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
             int phase = getPhase(bean);
             LifecycleGroup group = phases.get(phase);
             if (group == null) {
                 group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
                 phases.put(phase, group);
             }
             group.add(entry.getKey(), bean);
         }
     }
     if (!phases.isEmpty()) {
         List<Integer> keys = new ArrayList<Integer>(phases.keySet());
         Collections.sort(keys);
         for (Integer key : keys) {
             phases.get(key).start();
         }
     }
 }
  1. publishEvent

    當完成ApplicationContext初始化的時候,要通過 Spring 中的事件發佈機制來發布 ContextRefreshedEvent 事件,以保證對應的監聽器可以做進一步的邏輯處理。

protected void publishEvent(Object event, ResolvableType eventType) {
     Assert.notNull(event, "Event must not be null");
     if (logger.isTraceEnabled()) {
         logger.trace("Publishing event in " + getDisplayName() + ": " + event);
     }

     // Decorate event as an ApplicationEvent if necessary
     ApplicationEvent applicationEvent;
     if (event instanceof ApplicationEvent) {
         applicationEvent = (ApplicationEvent) event;
     }
     else {
         applicationEvent = new PayloadApplicationEvent<Object>(this, event);
         if (eventType == null) {
             eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
         }
     }

     // Multicast right now if possible - or lazily once the multicaster is initialized
     if (this.earlyApplicationEvents != null) {
         this.earlyApplicationEvents.add(applicationEvent);
     }
     else {
         getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
     }

     // Publish event via parent context as well...
     if (this.parent != null) {
         if (this.parent instanceof AbstractApplicationContext) {
             ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
         }
         else {
             this.parent.publishEvent(event);
         }
     }
 }

至此,Spring 容器就啓動完畢了,相信大家仔細看完這兩篇文章一定會對 Spring 的原理有更進一步的瞭解。

傳送門:

《Spring容器的基本實現之源碼分析-上篇》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章