Spring Bean的生命周期-實(shí)例化ApplicationContext(一)

Spring Bean的生命周期往深入去看,不是簡單的幾句話能講完,早就想寫相關(guān)的內(nèi)容,但一直覺得工作量不會低,就沒有動筆寫。拆成幾篇來寫,這樣也不好給自己太大的壓力。

image.png

主要分析,Spring容器的初始化過程,然后如何獲取Bean,到最終銷毀Bean整個過程經(jīng)歷了什么東西。

代碼

主要為了分析,更多的是深入源代碼中,代碼寫的就簡單一些

//SpringApp.java文件
public class SpringApp {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("app.xml");
        HelloWorld hello = (HelloWorld) applicationContext.getBean("hello");
        hello.sayHello();
        applicationContext.close();
    }
}

//HelloWorld 文件
public class HelloWorld {
    public void sayHello(){
        System.out.println("hello World");
    }
}

//app.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="hello" class="me.aihe.HelloWorld">

    </bean>
</beans>

文件結(jié)構(gòu)就是這個簡單,如下

image.png

過程分析

  1. 新建ClassPathXmlApplicationContext實(shí)例的時候,最終實(shí)例化的構(gòu)造方法如下
  • configLocations配置文件位置,支持字符串?dāng)?shù)組
  • refresh是否自動的刷新上下文,否則在配置之后要手動的調(diào)用refresh方法
  • parent 父級的上下文

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
        

其最終的實(shí)例化的父類為:

   //創(chuàng)建AbstractApplicationContext
    public AbstractApplicationContext() {
        this.resourcePatternResolver = getResourcePatternResolver();
    }

    public AbstractApplicationContext(ApplicationContext parent) {
        this();
        setParent(parent);
    }
    
    protected ResourcePatternResolver getResourcePatternResolver() {
        return new PathMatchingResourcePatternResolver(this);
    }
  1. 設(shè)置配置文件的位置, setConfigLocation(String location)
   //支持可變參數(shù),如果locations不存在,那么默認(rèn)為null
    public void setConfigLocations(String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];
            //處理配置文件的位置,稍作處理
            for (int i = 0; i < locations.length; i++) {
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }

  1. 刷新Context, 調(diào)用refresh()方法,這里先貼出來整個方法, Refreash方法是容器中非常重要的一個方法,一時間這里不好完全講說明白,先把每個方法的用途注釋寫上,接下來我們再一起看看其內(nèi)部是怎么回事
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 準(zhǔn)備刷新的Context.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            // 告訴子類刷新內(nèi)部的Bean Factory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            // 準(zhǔn)備好Context使用的Bean Factory
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                // 設(shè)置Bean的 postPorcess
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                // 調(diào)用BeanFactory的 postProcess
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 注冊Bean的PostProcess
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                //對上下文中的消息源進(jìn)行初始化
                initMessageSource();

                // Initialize event multicaster for this context.
                //初始化上下文的事件機(jī)制
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                //初始化其它特殊的beans
                onRefresh();

                // Check for listener beans and register them.
                //檢查這些Bean,并且向容器注冊
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                //實(shí)例化所有的非懶加載的 Singleton
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                // 發(fā)布相關(guān)的事件
                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.
                // 銷毀已經(jīng)創(chuàng)建的singletons避免對資源產(chǎn)生不好的影響
                destroyBeans();

                // Reset 'active' flag.
                //重置 active 標(biāo)志
                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...
                //重置所有的caches
                resetCommonCaches();
            }
        }
    }
涉及到類
  • PathMatchingResourcePatternResolver
  • StandardEnvironment
TODO
  • AbstractRefreshableConfigApplicationContext.resolvePath,其中涉及到了Environment.resolveRequiredPlaceholders(String path)

最后

讀代碼,如果條理清晰,是一件比較爽的工作,盡量不要急功近利,我們一步一步來,壓力都會比較小一點(diǎn)。

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容