Spring context的refresh函數執行過程分析


今天看了一下Spring Boot的run函數運行過程,發現它調用了Context中的refresh函數。所以先分析一下Spring context的refresh過程,然后再分析Spring boot中run的流程。

首先我們找到spring-context組件的AbstractApplicationContext類下的refresh函數:

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

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

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

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

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

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

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

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    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;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

prepareRefresh()

 

    protected void prepareRefresh() {
        // Switch to active.
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);

......

        // Initialize any placeholder property sources in the context environment.
        initPropertySources();

        // Validate that all properties marked as required are resolvable:
        // see ConfigurablePropertyResolver#setRequiredProperties
        getEnvironment().validateRequiredProperties();

        // Store pre-refresh ApplicationListeners...
        if (this.earlyApplicationListeners == null) {
            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
        }
        else {
            // Reset local application listeners to pre-refresh state.
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

可以看到,這個函數做了一些准備工作,記錄了refresh的開始時間,調用了留給子類重寫的initPropertySources()函數。

驗證了環境中必要的參數,並且將earlyListeners加入到應用程序的監聽器列表中。

 

obtainFreshBeanFactory() 

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        return getBeanFactory();
    }

可以看見,refreshBeanFactory()和getBeanFactory()都是abstract函數,這兩個函數設計出來就是為了讓子類重寫,根據子類實現具體功能,從函數名可以推斷出這兩個函數一個是用來初始化beanFactory,另外一個則是拿到beanFactory的實例,我們以AbstractRefreshableApplicationContext類的代碼為例:

refreshBeanFactory:

    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {//如果beanFactory已經被初始化過,則在此銷毀
            destroyBeans();
            closeBeanFactory();
        }
        try {//這里其實就是new了一個DefaultListableBeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            //客制化beanFactory,例如設置能否循環引用,能否重寫bean等
            customizeBeanFactory(beanFactory);
            //將xml中的bean定義加載到spring-core的注冊中心中
            loadBeanDefinitions(beanFactory);
            //設置beanFactory,供getBeanFactory取得
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

getBeanFactory:不難想象,這個函數從this類中拿到beanFactory實例並返回。

 

prepareBeanFactory(beanFactory)

 篇幅原因就不貼這部分代碼,實在太長,這個函數主要做了如下幾件事:

1. 設置了beanFactory的classloader

2. 設置了SpEL的解析器

3. 設置了PropertyEditor,這個是用來將xml里面的占位符解析成具體值的,例如xml里面寫<... value="${predefined-var}"/>,在PropertyEditor可以將${predefined-var}解析為某個具體值,並且到時候生成的beanDefinition對應的field就是這個具體的值。這一步會發生在xml被轉換為beanDefinition之前

4. 增加ApplicationContextAwareProcessor的BeanPostProcessor,這個是為了讓實現了ApplicationContextAware接口的bean在初始化后自身被注入當前的ApplicationContext,實現對自己所在的Context的感知

5. 忽略下述接口的依賴注入:

EnvironmentAware.class
EmbeddedValueResolverAware.class
ResourceLoaderAware.class
ApplicationEventPublisherAware.class
MessageSourceAware.class
ApplicationContextAware.class

觀察上述接口的特征,發現這些都是Aware系列接口,用於使Bean感知環境中的參數(例如當前Context)。自動裝配不會對這些接口進行處理,實際上實現了這些接口的類會在Spring中有專門的函數進行處理。

6. 對於一些特定的接口實現,定義默認的注入值:

BeanFactory.class
ResourceLoader.class
ApplicationEventPublisher.class
ApplicationContext.class

這些接口是用來獲取關於Spring本身相關的信息的,例如Spring本身的BeanFactory等。

7. 注冊一些環境相關的bean,例如systemProperties、systemEnvironment和environment

postProcessBeanFactory(beanFactory)

這個函數實際上是空的:

    /**
     * Modify the application context's internal bean factory after its standard
     * initialization. All bean definitions will have been loaded, but no beans
     * will have been instantiated yet. This allows for registering special
     * BeanPostProcessors etc in certain ApplicationContext implementations.
     * @param beanFactory the bean factory used by the application context
     */
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    }

通過上面的注釋,我們可以知道,當所有的xml已經被載入並且產生了對應的beanDefinition時,這個函數將會被調用,此時bean的實例都沒有產生,在此處可以對beanDefinition的屬性進行修改、抑或是注冊特別的beanPostProcessor用於對實例化的bean做最終處理。

這里函數留空是為了讓用戶能夠子類化,然后在里面寫入自己需要的修改,典型的模板設計模式

 

invokeBeanFactoryPostProcessors(beanFactory)

 調用所有在容器中注冊的BeanFactoryPostProcessor

 

registerBeanPostProcessors(beanFactory)

 注冊BeanPostProcessors,將所有在xml中定義的beanPostProcessors加入到當前BeanFactory的列表,以便在getBean的時候調用。

 

initMessageSource()

 初始化消息源

 

initApplicationEventMulticaster()

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.isTraceEnabled()) {
                logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isTraceEnabled()) {
                logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                        "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
            }
        }
    }

通過Spring容器得到一個applicationEventMulticaster,如果Spring容器沒有定義,則創建SimpleApplicationEventMulticaster作為applicationEventMulticaster。

通過SimpleApplicationEventMulticaster的代碼我們也能推斷出這個類的作用,就是向Context里面的EventListener發布消息:

    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        Executor executor = getTaskExecutor();
        //將當前的事件event發送給當前Context的每一個Listener
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            //如果有executor則使用executor執行
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                //否則直接在當前線程執行
                invokeListener(listener, event);
            }
        }
    }

 

onRefresh()

這是模板方法,留給子類實現並執行想要的操作

 

registerListeners()

這一步將注冊Listener,供前面initApplicationEventMulticaster注冊的EventMulticaster進行廣播,代碼如下:

    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);
            }
        }
    }

這段代碼將靜態注冊的Listener和Spring中注冊的Listener bean都添加到EventMulticaster中,這樣從EventMulticaster中發布的消息,每個Listener都能監聽到,典型的觀察者模式。

值得注意的是,Context中包含earlyApplicationEvents,所有的Listener就緒后,會先接收到這個事件。

 

finishBeanFactoryInitialization(beanFactory)

通過上面的注釋:Instantiate all remaining (non-lazy-init) singletons.

我們可以知道,這個方法初始化所有的非懶加載單例實例,代碼很復雜,后面會開一個專題分析這段代碼的。

 

finishRefresh()

從函數名可以知道這個是完成刷新,代碼如下:

    protected void finishRefresh() {
        // Clear context-level resource caches (such as ASM metadata from scanning).
        clearResourceCaches();

        // 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. 清空了資源緩存

2. 初始化了生命周期處理器,用於處理Bean生命周期

3. 使用生命周期處理器傳播刷新事件

4. 在Context內發布刷新事件

5. 將本Context注冊到ListBeansView中

 

至此,Context的refresh分析完畢,下一部該分析Spring Boot的run進行了什么操作了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM