深入理解 Spring 之源碼剖析IOC

作為Java程序員询一,Spirng我們?cè)偈煜げ贿^六剥,可以說比自己的女朋友還要親密趣避,每天都會(huì)和他在一起庞呕,然而我們真的了解spring嗎?

我們都知道程帕,Spring的核心是IOC和AOP住练,但樓主認(rèn)為,如果從這兩個(gè)核心中挑選一個(gè)更重要的愁拭,那非IOC莫屬讲逛。AOP 也是依賴于IOC,從某些角度講岭埠,AOP就是IOC的一個(gè)擴(kuò)展功能盏混。

什么是IOC? IOC解決了什么問題惜论?IOC的原理是什么许赃?Spring的IOC是怎么實(shí)現(xiàn)的?今天我們將會(huì)將這幾個(gè)問題一起解決馆类。

1. 什么是IOC混聊?

控制反轉(zhuǎn)(Inversion of Control,縮寫為IoC)乾巧,是面向?qū)ο缶幊讨械囊环N設(shè)計(jì)原則句喜,可以用來(lái)減低計(jì)算機(jī)代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection沟于,簡(jiǎn)稱DI)咳胃,還有一種方式叫“依賴查找”(Dependency Lookup)。通過控制反轉(zhuǎn)旷太,對(duì)象在被創(chuàng)建的時(shí)候展懈,由一個(gè)調(diào)控系統(tǒng)內(nèi)所有對(duì)象的外界實(shí)體,將其所依賴的對(duì)象的引用傳遞給它供璧。也可以說标沪,依賴被注入到對(duì)象中。

這是維基百科的說法嗜傅,樓主按照自己的思路分析一下IOC金句,樓主認(rèn)為,分析一個(gè)問題吕嘀,或者說證明一個(gè)事情违寞,有2種方法贞瞒,一是正向驗(yàn)證,即按照該事務(wù)的邏輯去驗(yàn)證正確性趁曼,還有一種是反向驗(yàn)證军浆,證明該事務(wù)是否正確。樓主想反向證明IOC挡闰,我們提出一個(gè)疑問:如果沒有IOC會(huì)怎么樣乒融?

想象一下,在沒有IOC的世界里摄悯,我們的系統(tǒng)會(huì)有大量的對(duì)象赞季,這些對(duì)象有些是數(shù)據(jù),有些是處理數(shù)據(jù)的奢驯,各個(gè)對(duì)象相互依賴申钩,我們需要控制他們的依賴關(guān)系,什么時(shí)候new 瘪阁,什么時(shí)候銷毀撒遣,什么時(shí)候需要單例,什么時(shí)候不需要單例等等這些問題管跺,你能想象嗎义黎,當(dāng)你一個(gè)系統(tǒng)有幾千個(gè)類,你如何管理他們的依賴關(guān)系豁跑,說起依賴轩缤,我們可能會(huì)想起 maven 或者 gradle,他們管理著我們的 jar 包依賴贩绕,而我們的系統(tǒng)代碼呢?想想都頭大壶愤。

但是如果有一種東西淑倾,他能夠幫助我們管理所有類的創(chuàng)建,銷毀征椒,是否是單例模式娇哆,類與類之間的多層依賴關(guān)系(在我們的MVC框架中,3層依賴已經(jīng)是最少)勃救,那該多好碍讨,我們只需要關(guān)注業(yè)務(wù)邏輯。于是 蒙秒,IOC誕生了勃黍。

2. IOC 解決了什么問題?

簡(jiǎn)單來(lái)說, IOC 解決了類與類之間的依賴關(guān)系晕讲。程序員將控制類與類之間依賴的權(quán)利交給了IOC覆获,即:控制被反轉(zhuǎn)了马澈。

3. IOC 的原理是什么?

其實(shí) IOC 的原理很簡(jiǎn)單弄息,底層就是java的反射痊班。給定一個(gè)字符串能創(chuàng)建一個(gè)實(shí)例,利用set方法對(duì)實(shí)例的依賴進(jìn)行注入摹量。

我們來(lái)一段代碼證明一下是多么的簡(jiǎn)單:


可以看到該代碼非常的簡(jiǎn)單涤伐,但實(shí)際上IOC 就是這么簡(jiǎn)單,在真正的開發(fā)中缨称,我們只需要在配置文件給定一個(gè)類名字符串凝果,就什么都不用管了,對(duì)象就會(huì)創(chuàng)建出來(lái)具钥,系統(tǒng)啟動(dòng)完畢之后豆村,我們只需要直接使用該對(duì)象就好了,不必自己去new骂删。解決了我們的對(duì)象創(chuàng)建問題掌动。我們通過反射調(diào)用該方法的setText方法,完成了依賴注入宁玫。我們不再需要去new粗恢,然后去set,IOC 已經(jīng)為我們做好了一切欧瘪。

介紹完了幾個(gè)基本知識(shí)眷射,其實(shí)都是為我們今天的重頭戲做準(zhǔn)備,Spring的IOC是怎么實(shí)現(xiàn)的佛掖?

4. Spring的IOC是怎么實(shí)現(xiàn)的妖碉?

這是一個(gè)浩大的問題,雖然底層實(shí)現(xiàn)可能就那么幾行代碼芥被,但樓主說過欧宜,所有框架的底層技術(shù)都很簡(jiǎn)單沟沙,但是我們的框架大師們?yōu)榱塑浖慕研圆绲唬瑪U(kuò)展性和性能,做了無(wú)數(shù)的優(yōu)化榴捡,我們的系統(tǒng)源碼也就變得越來(lái)越復(fù)雜匹中,spirng的 release 版本至今已經(jīng)到了 5.0.3夏漱,和最初的 interface21 已經(jīng)有了翻天復(fù)地的變化,現(xiàn)在也有了springboot顶捷, springcloud挂绰,儼然一個(gè)龐大的spring家族,想分析源碼的我們?cè)搹哪睦锵率帜兀?/p>

萬(wàn)劍歸宗服赎,始于一處扮授。

Bean芳室。

我們要研究spring的IOC,我們要了解的就是spring的bean刹勃,這是spring的核心的核心堪侯。雖然bena依賴著context 模塊提供bean的環(huán)境,依賴core 提供著一系列強(qiáng)化的工具荔仁。但今天我們不關(guān)心伍宦,我們只關(guān)系bean。只關(guān)心IOC乏梁。就像這個(gè)信息過載次洼,技術(shù)不斷更新的時(shí)代,程序們需要有自己的判斷遇骑,自己需要研究什么卖毁,什么是最重要的?扯遠(yuǎn)了落萎。

在開始研究源碼之前亥啦,樓主有必要介紹一下IOC的一些核心組件,否則一旦進(jìn)入源碼练链,就會(huì)被細(xì)節(jié)捆住翔脱,無(wú)法從宏觀的角度理解IOC。

  1. BeanFactory:這是IOC容器的接口定義媒鼓,如果將IOC容器定位為一個(gè)水桶届吁,那么BeanFactory 就定義了水桶的基本功能,能裝水绿鸣,有把手疚沐。這是最基本的,他的實(shí)現(xiàn)類可以拓展水桶的功能潮模。
  2. ApplicationContext:這是我們最常見的亮蛔,上面我們說水桶,BeanFactory是最基本的水桶再登,而 ApplicationContext 則是擴(kuò)展后的水桶,它通過繼承 MessageSource晾剖,ResourceLoader锉矢,ApplicationEventPublisher 接口,在BeanFactory 簡(jiǎn)單IOC容器的基礎(chǔ)上添加了許多對(duì)高級(jí)容器的支持齿尽。
  3. BeanDefinition:我們知道沽损,每個(gè)bean都有自己的信息,各個(gè)屬性循头,類名绵估,類型炎疆,是否單例,這些都是bena的信息国裳,spring中如何管理bean的信息呢形入?對(duì),就是 BeanDefinition缝左, Spring通過定義 BeanDefinition 來(lái)管理基于Spring的應(yīng)用中的各種對(duì)象以及他們直接的相互依賴關(guān)系亿遂。BeanDefinition 抽象了我們對(duì) Bean的定義,是讓容器起作用的主要數(shù)據(jù)類型渺杉。對(duì) IOC 容器來(lái)說蛇数,BeanDefinition 就是對(duì)依賴反轉(zhuǎn)模式中管理的對(duì)象依賴關(guān)系的數(shù)據(jù)抽象。也是容器實(shí)現(xiàn)依賴反轉(zhuǎn)功能的核心數(shù)據(jù)結(jié)構(gòu)是越。

1. 搭建源碼研究環(huán)境

樓主研究源碼的思路有2個(gè)耳舅,一個(gè)是創(chuàng)建一個(gè)簡(jiǎn)單的spirng maven 項(xiàng)目,還有一個(gè)是直接從 spirng 的github 上 clone 源碼倚评。

這是樓主的普通 maven 項(xiàng)目:

這是樓主的 clone 的 spring-framework 源碼:

注意:clone 該源碼的時(shí)候浦徊,樓主很艱辛,因?yàn)橐茖W(xué)上網(wǎng)蔓纠,否則 gradle 無(wú)法下載依賴會(huì)導(dǎo)致報(bào)錯(cuò)辑畦。如果各位無(wú)法科學(xué)上網(wǎng),可以使用 maven 項(xiàng)目勉強(qiáng)學(xué)習(xí)腿倚。

2. 開啟研究源碼第一步

我們打開spring-framework 源碼纯出。

還記的我們初學(xué)spring的寫的第一行代碼是什么嗎?

怎么寫配置文件樓主就不說了敷燎,我們回憶一下我們最初學(xué)spring的時(shí)候暂筝,雖然現(xiàn)在都是2017年了,我們都用springboot硬贯,都是用注解了焕襟,但spring的核心代碼還是 spring 之父 Rod Johnson 在 2001 年寫的。所以不影響我們學(xué)習(xí)spring 的核心饭豹。

我們仔細(xì)看看該代碼(該代碼位置必須在spring-context模塊下):

package test;

import org.springframework.beans.tests.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {

        ApplicationContext ctx = new FileSystemXmlApplicationContext
                ("spring-beans/src/test/resources/beans.xml");
        System.out.println("number : " + ctx.getBeanDefinitionCount());
        ((Person) ctx.getBean("person")).work();
    }
}

熟悉的 ApplicatContext 鸵赖,看名字是應(yīng)用上下文,什么意思呢拄衰?就是spirng整個(gè)運(yùn)行環(huán)境的背景它褪,好比一場(chǎng)舞臺(tái)劇,ApplicatContext 就是舞臺(tái)翘悉,IOC 管理的Bean 就是演員茫打,Core 就是道具。而ApplicatContext 的標(biāo)準(zhǔn)實(shí)現(xiàn)是 FileSystemXmlApplicationContext。

該類的構(gòu)造方法中包含了容器的啟動(dòng)老赤,IOC的初始化轮洋。所以我們 debug 啟動(dòng)該項(xiàng)目,運(yùn)行main方法抬旺。打好斷點(diǎn)弊予。

3. 從 FileSystemXmlApplicationContext 開始剖析

從這里開始,我們即將進(jìn)入復(fù)雜的源碼嚷狞。

我們進(jìn)入 FileSystemXmlApplicationContext 的構(gòu)造方法:

可以看到該構(gòu)造方法被重載了块促,可以傳遞 configLocation 數(shù)組,也就是說床未,可以傳遞過個(gè)配置文件的地址竭翠。默認(rèn)刷新為true,parent 容器為null薇搁。進(jìn)入另一個(gè)構(gòu)造器:

該構(gòu)造器做了2件事情斋扰,一是設(shè)置配置文件,二是刷新容器啃洋,我們可以感覺到传货,refresh 方法才是初始化容器的重要方法。我們進(jìn)入該方法看看:該方法是 FileSystemXmlApplicationContext 的父類 AbstractApplicationContext 的方法宏娄。

4. AbstractApplicationContext.refresh() 方法實(shí)現(xiàn)

/**
     *
     * 1. 構(gòu)建Be按Factory问裕,以便產(chǎn)生所需要的bean定義實(shí)例
     * 2. 注冊(cè)可能感興趣的事件
     * 3. 創(chuàng)建bean 實(shí)例對(duì)象
     * 4. 觸發(fā)被監(jiān)聽的事件
     *
     */
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 為刷新準(zhǔn)備應(yīng)用上下文
            prepareRefresh();
            // 告訴子類刷新內(nèi)部bean工廠,即在子類中啟動(dòng)refreshBeanFactory()的地方----創(chuàng)建bean工廠孵坚,根據(jù)配置文件生成bean定義
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            // 在這個(gè)上下文中使用bean工廠
            prepareBeanFactory(beanFactory);

            try {
                // 設(shè)置BeanFactory的后置處理器
                postProcessBeanFactory(beanFactory);
                // 調(diào)用BeanFactory的后處理器粮宛,這些后處理器是在Bean定義中向容器注冊(cè)的
                invokeBeanFactoryPostProcessors(beanFactory);
                // 注冊(cè)Bean的后處理器,在Bean創(chuàng)建過程中調(diào)用
                registerBeanPostProcessors(beanFactory);
                //對(duì)上下文的消息源進(jìn)行初始化
                initMessageSource();
                // 初始化上下文中的事件機(jī)制
                initApplicationEventMulticaster();
                // 初始化其他的特殊Bean
                onRefresh();
                // 檢查監(jiān)聽Bean并且將這些Bean向容器注冊(cè)
                registerListeners();
                // 實(shí)例化所有的(non-lazy-init)單件
                finishBeanFactoryInitialization(beanFactory);
                //  發(fā)布容器事件卖宠,結(jié)束refresh過程
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }
                // 為防止bean資源占用巍杈,在異常處理中,銷毀已經(jīng)在前面過程中生成的單件bean
                destroyBeans();
                // 重置“active”標(biāo)志
                cancelRefresh(ex);
                throw ex;
            }

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

可以說該方法就是整個(gè)IOC容器初始化的所有邏輯扛伍。因此筷畦,如果讀懂了該方法的每一行代碼,就了解了spring的整個(gè)功能刺洒。該方法的調(diào)用層次之深可以想象一下鳖宾。

我們先大致說下該方法的步驟:

  1. 構(gòu)建BeanFactory,以便于產(chǎn)生所需的 Bean逆航。
  2. 注冊(cè)可能感興趣的事件鼎文。
  3. 常見Bean實(shí)例對(duì)象。
  4. 觸發(fā)被監(jiān)聽的事件纸泡。

我們一個(gè)個(gè)來(lái)看:
首先構(gòu)建BeanFactory漂问,在哪里實(shí)現(xiàn)的呢?也就是obtainFreshBeanFactory 方法女揭,返回了一個(gè)ConfigurableListableBeanFactory蚤假,該方法調(diào)用了 refreshBeanFactory() ,該方法是個(gè)模板方法吧兔,交給了 AbstractRefreshableApplicationContext 去實(shí)現(xiàn)磷仰。我們看看該方法實(shí)現(xiàn):

@Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            // 如果存在就銷毀
            destroyBeans();
            closeBeanFactory();
        }
        try {
            // new DefaultListableBeanFactory(getInternalParentBeanFactory())
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            // 設(shè)置序列化
            beanFactory.setSerializationId(getId());
            // 定制的BeanFactory
            customizeBeanFactory(beanFactory);
            // 使用BeanFactory加載bean定義 AbstractXmlApplicationContext
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

可以看到BeanFactory的創(chuàng)建過程,首先判斷是否存在了 BeanFactory境蔼,如果有則銷毀重新創(chuàng)建灶平,調(diào)用 createBeanFactory 方法,該方法中就是像注釋寫的:創(chuàng)建了 DefaultListableBeanFactory 箍土,也既是說逢享,DefaultListableBeanFactory 就是 BeanFactory的默認(rèn)實(shí)現(xiàn)。然后我們看到一個(gè)很感興趣的方法吴藻,就是 loadBeanDefinitions(beanFactory)瞒爬,看名字是加載 Definitions,這個(gè)我們很感興趣沟堡,我們之前說過侧但, Definition 是核心之一,代表著 IOC 中的基本數(shù)據(jù)結(jié)構(gòu)航罗。該方法也是個(gè)抽象方法禀横,默認(rèn)實(shí)現(xiàn)是 AbstractXmlApplicationContext ,我們看看該方法實(shí)現(xiàn):

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }

該方法我沒有寫中文注釋粥血,我們看看英文注釋: 首先創(chuàng)建一個(gè) XmlBeanDefinitionReader 柏锄,用于讀取XML中配置,設(shè)置了環(huán)境立莉,資源加載器绢彤,最后初始化,加載蜓耻∶2埃可以說,該方法將加載刹淌,解析Bean的定義饶氏,也就是把用戶定義的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化為 IOC容器中的特定數(shù)據(jù)結(jié)構(gòu)。而我們關(guān)心的則是最后一行的 loadBeanDefinitions(beanDefinitionReader) 方法有勾。

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {// 加載給定的路徑文件
            reader.loadBeanDefinitions(configLocations);
        }
    }

該方法會(huì)略過第一個(gè)if塊疹启,進(jìn)入第二個(gè)if塊,進(jìn)入 AbstractBeanDefinitionReader.loadBeanDefinitions(String... locations) 方法蔼卡,該方法內(nèi)部循環(huán)加載配置文件:

    @Override
    public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        Assert.notNull(locations, "Location array must not be null");
        int counter = 0;
        for (String location : locations) {
            counter += loadBeanDefinitions(location);
        }
        return counter;
    }

我們關(guān)心的是 for 循環(huán)中的loadBeanDefinitions(location)方法喊崖,該方法核心邏輯在 AbstractBeanDefinitionReader.loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) 方法中:

    public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        }

        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            try {
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                int loadCount = loadBeanDefinitions(resources);// 根據(jù)配置文件加載bean定義
                if (actualResources != null) {
                    for (Resource resource : resources) {
                        actualResources.add(resource);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                }
                return loadCount;
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(
                        "Could not resolve bean definition resource pattern [" + location + "]", ex);
            }
        }
        else {
            // Can only load single resources by absolute URL.
            Resource resource = resourceLoader.getResource(location);
            int loadCount = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
            }
            return loadCount;
        }
    }

該方法首先獲取資源加載器,然后進(jìn)入 if 塊,獲取資源數(shù)組荤懂,調(diào)用 loadBeanDefinitions(resources) 茁裙,根據(jù)配置文件加載Bean定義。進(jìn)入該方法后节仿,循環(huán)加載resource 資源數(shù)組晤锥,進(jìn)入 loadBeanDefinitions(resource) 方法中,最后進(jìn)入到 XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) 方法中廊宪,該方法主要調(diào)用 doLoadBeanDefinitions(inputSource, encodedResource.getResource()) 方法矾瘾。我們有必要看看該方法實(shí)現(xiàn):

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            Document doc = doLoadDocument(inputSource, resource);
            return registerBeanDefinitions(doc, resource);// 真正的注冊(cè)bean
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        }
        catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from " + resource + " is invalid", ex);
        }
        catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from " + resource, ex);
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from " + resource, ex);
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from " + resource, ex);
        }
    }

可以看出該方法主要邏輯是根據(jù)輸入流加載 Document 文檔對(duì)象,然后根據(jù)得到的文檔對(duì)象注冊(cè)到容器箭启,因此我們看看倒是是如何注冊(cè)到容器的壕翩,該方法首先創(chuàng)建一個(gè) BeanDefinitionDocumentReader, 用于讀取 BeanDefinition傅寡,該對(duì)象會(huì)調(diào)用 registerBeanDefinitions(doc, createReaderContext(resource)) 方法戈泼,該方法最后從文檔對(duì)象總獲取根元素,最后調(diào)用
DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(root) 進(jìn)行注冊(cè)赏僧。該方法最核心的邏輯就是調(diào)用 parseBeanDefinitions(root, this.delegate)大猛,我們看看該方法具體實(shí)現(xiàn):

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);// 解析
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

該方法就是一個(gè)解析XML 文檔的步驟,核心是調(diào)用 parseDefaultElement(ele, delegate)淀零,我們進(jìn)入該方法查看挽绩,該方法調(diào)用了 processBeanDefinition(ele, delegate) 方法進(jìn)行解析。我們有必要看看該方法:

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);// 解析
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());// 開始注冊(cè)
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

首先創(chuàng)建一個(gè) BeanDefinitionHolder驾中,該方法會(huì)調(diào)用 BeanDefinitionReaderUtils.registerBeanDefinition 方法唉堪, 最后執(zhí)行容器通知事件。該靜態(tài)方法實(shí)現(xiàn)如下:

     */
    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // Register bean definition under primary name.
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// 注冊(cè)

        // Register aliases for bean name, if any.
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

可以看到首先從bean的持有者那里獲取了beanName肩民,然后調(diào)用 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())唠亚, 將bena的名字和 BeanDefinition 注冊(cè),我們看看最后的邏輯:

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition oldBeanDefinition;

        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
        if (oldBeanDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                        "': There is already [" + oldBeanDefinition + "] bound.");
            }
            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(oldBeanDefinition)) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                // Still in startup registration phase // 最終放進(jìn)這個(gè)map 實(shí)現(xiàn)注冊(cè)
                this.beanDefinitionMap.put(beanName, beanDefinition);// 走這里 // private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

該方法可以說是注冊(cè)bean的最后一步持痰,將beanName和 beanDefinition 放進(jìn)一個(gè) ConcurrentHashMap(256) 中灶搜。

那么這個(gè) beanDefinition 是時(shí)候創(chuàng)建的呢? 就是在 DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法中工窍,在這里創(chuàng)建了 BeanDefinitionHolder割卖, 而該實(shí)例中解析Bean并將Bean 保存在該對(duì)象中。所以稱為持有者患雏。該實(shí)例會(huì)調(diào)用 parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) 方法鹏溯,該方法用于解析XML文件并創(chuàng)建一個(gè) BeanDefinitionHolder 返回抄肖,該方法會(huì)調(diào)用 parseBeanDefinitionElement(ele, beanName, containingBean) 方法岖研, 我們看看該方法:

    @Nullable
    public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, @Nullable BeanDefinition containingBean) {

        this.parseState.push(new BeanEntry(beanName));

        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();// 類全限定名稱
        }
        String parent = null;
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

        try {
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);// 創(chuàng)建

            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

            parseMetaElements(ele, bd);
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

            parseConstructorArgElements(ele, bd);
            parsePropertyElements(ele, bd);
            parseQualifierElements(ele, bd);

            bd.setResource(this.readerContext.getResource());
            bd.setSource(extractSource(ele));

            return bd;
        }
        catch (ClassNotFoundException ex) {
            error("Bean class [" + className + "] not found", ele, ex);
        }
        catch (NoClassDefFoundError err) {
            error("Class that bean class [" + className + "] depends on not found", ele, err);
        }
        catch (Throwable ex) {
            error("Unexpected failure during bean definition parsing", ele, ex);
        }
        finally {
            this.parseState.pop();
        }

        return null;
    }

我們看看該方法,可以看到走敌,該方法從XML元素中取出 class 元素,然后拿著className調(diào)用 createBeanDefinition(className, parent) 方法颜阐,該方法核心是調(diào)用 BeanDefinitionReaderUtils.createBeanDefinition 方法悬槽,我們看看該方法:

    public static AbstractBeanDefinition createBeanDefinition(
            @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

        GenericBeanDefinition bd = new GenericBeanDefinition();// 泛型的bean定義,也就是最終生成的bean定義瞬浓。
        bd.setParentName(parentName);
        if (className != null) {
            if (classLoader != null) {
                bd.setBeanClass(ClassUtils.forName(className, classLoader));// 設(shè)置Class 對(duì)象
            }
            else {
                bd.setBeanClassName(className);
            }
        }
        return bd;
    }

該方法很簡(jiǎn)單,創(chuàng)建一個(gè) Definition 的持有者蓬坡,然后設(shè)置該持有者的Class對(duì)象猿棉,該對(duì)象就是我們?cè)谂渲梦募信渲玫腃lass對(duì)象。最后返回屑咳。

到這里萨赁,我們一走完了第一步,創(chuàng)建bean工廠兆龙,生成Bean定義杖爽。但還沒有實(shí)例化該類。

5. 如何創(chuàng)建Bean實(shí)例并構(gòu)建Bean的依賴關(guān)系網(wǎng)

我們剛剛創(chuàng)建了Bean工廠紫皇,并創(chuàng)建 BeanDefinitions 放進(jìn)Map里慰安,以beanName為key。那么我們現(xiàn)在有了Bean定義聪铺,但還沒有實(shí)例化焕,也沒有構(gòu)建Bean與Bean之間的依賴關(guān)系。我們知道铃剔,構(gòu)建依賴關(guān)系是 IOC 的一個(gè)重要的任務(wù)撒桨,我們?cè)趺茨芊胚^。那么是在哪里做的呢键兜?在 finishBeanFactoryInitialization(beanFactory) 方法中凤类。該方法中重要的一步是 : beanFactory.preInstantiateSingletons(),我們有必要看看該方法實(shí)現(xiàn):

    @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<>(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);// 注意:FactoryBean
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
                                ((SmartFactoryBean<?>) factory).isEagerInit(),
                                getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
                else {
                    getBean(beanName);// 創(chuàng)建bean
                }
            }
        }

        // 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((PrivilegedAction<Object>) () -> {
                        smartSingleton.afterSingletonsInstantiated();
                        return null;
                    }, getAccessControlContext());
                }
                else {
                    smartSingleton.afterSingletonsInstantiated();
                }
            }
        }
    }

該方法首先循環(huán)所有的BeanNames普气,并且調(diào)用getBean方法谜疤,該方法實(shí)際上就是創(chuàng)建bean并遞歸構(gòu)建依賴關(guān)系。該方法會(huì)調(diào)用 doGetBean(name, null, null, false)现诀,我們進(jìn)入該方法查看茎截,該方法很長(zhǎng),樓主挑選重要代碼:

String[] dependsOn = mbd.getDependsOn();// 
if (dependsOn != null) {
    for (String dep : dependsOn) {
        if (isDependent(beanName, dep)) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
        }
        registerDependentBean(dep, beanName);
        getBean(dep);// 遞歸
    }
}


// Create bean instance.
if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            // Explicitly remove instance from singleton cache: It might have been put there
            // eagerly by the creation process, to allow for circular reference resolution.
            // Also remove any beans that received a temporary reference to the bean.
            destroySingleton(beanName);
            throw ex;
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

可以看到赶盔,該方法首先會(huì)獲取依賴關(guān)系企锌,拿著依賴的BeanName 遞歸調(diào)用 getBean方法,直到調(diào)用 getSingleton 方法返回依賴bean于未,而 getSingleton 方法的參數(shù)是 createBean 返回的實(shí)例撕攒,該方法內(nèi)部調(diào)用 AbstractAutowireCapableBeanFactory.doCreateBean 方法:

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }

該方法很長(zhǎng)陡鹃,我們只關(guān)注二行代碼:

  1. instanceWrapper = createBeanInstance(beanName, mbd, args) 創(chuàng)建實(shí)例。
  2. populateBean(beanName, mbd, instanceWrapper) 抖坪, 該方法用于填充Bean萍鲸,該方法可以就是說就是發(fā)生依賴注入的地方。

我們看看 createBeanInstance 方法:

    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // Make sure bean class is actually resolved at this point.
        Class<?> beanClass = resolveBeanClass(mbd, beanName);

        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }

        Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName);
        }

        if (mbd.getFactoryMethodName() != null)  {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        // Shortcut when re-creating the same bean...
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        if (resolved) {
            if (autowireNecessary) {
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                return instantiateBean(beanName, mbd);
            }
        }

        // Need to determine the constructor...
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        // No special handling: simply use no-arg constructor.
        return instantiateBean(beanName, mbd);
    }

該方法的doc注釋是這樣介紹的:為指定的bean創(chuàng)建一個(gè)新的實(shí)例擦俐,使用適當(dāng)?shù)膶?shí)例化策略:工廠方法脊阴、構(gòu)造函數(shù)自動(dòng)裝配或簡(jiǎn)單實(shí)例化。我們看蚯瞧,該方法首先創(chuàng)建Class 對(duì)象嘿期,然后獲取構(gòu)造器對(duì)象,最后調(diào)用 instantiateBean(beanName, mbd) 方法埋合,我們看看該方法實(shí)現(xiàn):

    protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
        try {
            Object beanInstance;
            final BeanFactory parent = this;
            if (System.getSecurityManager() != null) {
                beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                        getInstantiationStrategy().instantiate(mbd, beanName, parent),
                        getAccessControlContext());
            }
            else {
                beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
            }
            BeanWrapper bw = new BeanWrapperImpl(beanInstance);
            initBeanWrapper(bw);
            return bw;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
        }
    }

該方法核心邏輯是 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent)备徐,攜帶BeanName ,RootBeanDefinition ,發(fā)揮的策略對(duì)象是 SimpleInstantiationStrategy,該方法內(nèi)部調(diào)用靜態(tài)方法
BeanUtils.instantiateClass(constructorToUse)甚颂, 組后調(diào)用 Constructor 的 newInstance 方法蜜猾, 也就是最終使用反射創(chuàng)建了該實(shí)例:

    public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
        Assert.notNull(ctor, "Constructor must not be null");
        try {
            ReflectionUtils.makeAccessible(ctor);
            return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
                    KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
        }
        catch (InstantiationException ex) {
            throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
        }
        catch (IllegalAccessException ex) {
            throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
        }
        catch (IllegalArgumentException ex) {
            throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
        }
        catch (InvocationTargetException ex) {
            throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
        }
    }

該方法會(huì)判斷是否是 Kotlin 類型。如果不是振诬,則調(diào)用構(gòu)造器的實(shí)例方法蹭睡。

到這里,我們的實(shí)例已經(jīng)創(chuàng)建赶么。但是我們的實(shí)例的依賴還沒有設(shè)置棠笑,剛剛我們?cè)?doCreateBean 方法說關(guān)心2行代碼:

  1. instanceWrapper = createBeanInstance(beanName, mbd, args) 創(chuàng)建實(shí)例。
  2. populateBean(beanName, mbd, instanceWrapper) 禽绪, 該方法用于填充Bean蓖救,該方法可以就是說就是發(fā)生依賴注入的地方。

我們已經(jīng)解析了第一個(gè)印屁,現(xiàn)在看第二個(gè)方法:

我們看看該方法:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        if (bw == null) {
            if (mbd.hasPropertyValues()) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
            else {
                // Skip property population phase for null instance.
                return;
            }
        }

        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used, for example,
        // to support styles of field injection.
        boolean continueWithPropertyPopulation = true;

        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }

        if (!continueWithPropertyPopulation) {
            return;
        }

        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

            // Add property values based on autowire by name if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }

            // Add property values based on autowire by type if applicable.
            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }

            pvs = newPvs;
        }

        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

        if (hasInstAwareBpps || needsDepCheck) {
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            if (hasInstAwareBpps) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }

        if (pvs != null) {
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }

該方法核心邏輯是 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null)循捺, 即獲取該bean的所有屬性,也就是我們配置property元素雄人。最后執(zhí)行 applyPropertyValues(beanName, mbd, bw, pvs) 方法从橘。注意,現(xiàn)在的PropertyValues 都是字符串础钠,沒有值的恰力,這個(gè)方法的作用就是獲取值,關(guān)鍵代碼:Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue)旗吁,該方法會(huì)獲取 pvName 所對(duì)應(yīng)的容器value踩萎,該方法內(nèi)部會(huì)調(diào)用 BeanWrapperImpl.resolveReference(argName, ref) 方法,我們看看該方法:

    @Nullable
    private Object resolveReference(Object argName, RuntimeBeanReference ref) {
        try {
            Object bean;
            String refName = ref.getBeanName();
            refName = String.valueOf(doEvaluate(refName));
            if (ref.isToParent()) {
                if (this.beanFactory.getParentBeanFactory() == null) {
                    throw new BeanCreationException(
                            this.beanDefinition.getResourceDescription(), this.beanName,
                            "Can't resolve reference to bean '" + refName +
                            "' in parent factory: no parent factory available");
                }
                bean = this.beanFactory.getParentBeanFactory().getBean(refName);
            }
            else {
                bean = this.beanFactory.getBean(refName);
                this.beanFactory.registerDependentBean(refName, this.beanName);
            }
            if (bean instanceof NullBean) {
                bean = null;
            }
            return bean;
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    this.beanDefinition.getResourceDescription(), this.beanName,
                    "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
        }
    }

其中有一行熟悉的代碼:bean = this.beanFactory.getBean(refName)很钓,對(duì)香府,這里就是發(fā)生遞歸的地方董栽。該方法會(huì)拿著屬性名稱從容器中獲取實(shí)例。

我們回到 applyPropertyValues 方法企孩。此時(shí)deepCopy 集合已經(jīng)有值了锭碳,不再僅僅是字符串了。然后調(diào)用 setPropertyValues(new MutablePropertyValues(deepCopy)) 方法勿璃, 該方法會(huì)調(diào)用 AbstractPropertyAccessor.setPropertyValues 方法完成注入擒抛,而該方法會(huì)循環(huán)元素列表, 循環(huán)中調(diào)用 setPropertyValue(PropertyValue pv) 方法补疑, 該方法最后會(huì)調(diào)用 nestedPa.setPropertyValue(tokens, pv) 方法歧沪, 該方法又會(huì)調(diào)用 processLocalProperty(tokens, pv) 方法,該方法最后又會(huì)調(diào)用 ph.setValue(valueToApply) 方法癣丧,也就是BeanWrapperImpl.setValue() 方法,終于栈妆,我們要看到反射了胁编,看到反射說明到了盡頭。

        @Override
        public void setValue(final @Nullable Object value) throws Exception {
            final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
                    ((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
                    this.pd.getWriteMethod());
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    ReflectionUtils.makeAccessible(writeMethod);
                    return null;
                });
                try {
                    AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
                            writeMethod.invoke(getWrappedInstance(), value), acc);
                }
                catch (PrivilegedActionException ex) {
                    throw ex.getException();
                }
            }
            else {
                ReflectionUtils.makeAccessible(writeMethod);
                writeMethod.invoke(getWrappedInstance(), value);
            }
        }

該方法是最后一步鳞尔,我們看到該方法會(huì)找的set方法嬉橙,然后調(diào)用 Method 的 invoke 方法,完成屬性注入寥假。

真的不容易市框。

5. 總結(jié)

我們從源碼層面剖析 IOC 的初始化過程,也了解了 IOC 的底層原理實(shí)現(xiàn), 我們總結(jié)一下: Spring 的 Bean 其實(shí)就是 BeanDefinition, 在 Bean 的創(chuàng)建和依賴注入的過程中, 需要根據(jù) BeanDefinition 的信息來(lái)遞歸的完成依賴注入, 從我們分析的代碼可以看到,這些遞歸都是以 getBean() 為入口的, 一個(gè)遞歸是在上下文體系中查找需要的 Bean 和創(chuàng)建 Bean 的遞歸調(diào)用, 另一個(gè) Bean 實(shí)在依賴注入時(shí),通過遞歸調(diào)用容器的 getBean 方法, 得到當(dāng)前的依賴 Bean, 同時(shí)也觸發(fā)對(duì)依賴 Bean 的創(chuàng)建和注入. 在對(duì) Bean 的屬性盡心依賴注入時(shí), 解析的過程也是一個(gè)遞歸的過程, 這樣, 根據(jù)依賴關(guān)系, 一層一層的完成 Bean 的創(chuàng)建和注入, 知道最后完成當(dāng)前 Bean 的創(chuàng)建, 有了這個(gè)頂層 Bean 的創(chuàng)建和對(duì)他的屬性依賴注入的完成, 意味著當(dāng)前 Bean 相關(guān)的整個(gè)依賴鏈的注入也完成了.

總結(jié)一下 IOC 的初始化過程吧:

  1. 資源(Resource)定位;
  2. BeanDefinition 的載入和 BeanFactory 的構(gòu)造.
  3. 想 IOC 容器(BeanFactory)注冊(cè) BeanDefinition.
  4. 根據(jù) lazy-init 屬性初始化 Bean 實(shí)例和依賴注入.

現(xiàn)在回過頭看看, 我們已經(jīng)了解了 Spring IOC 的設(shè)計(jì), 那么我們自己可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 IOC 嗎? 樓主想試試, 并且樓主已經(jīng)寫好了, 下篇, 和大家一起實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 IOC.

Good Luck!!!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市糕韧,隨后出現(xiàn)的幾起案子枫振,更是在濱河造成了極大的恐慌,老刑警劉巖萤彩,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粪滤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡雀扶,警方通過查閱死者的電腦和手機(jī)杖小,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)愚墓,“玉大人予权,你說我怎么就攤上這事±瞬幔” “怎么了扫腺?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)村象。 經(jīng)常有香客問我斧账,道長(zhǎng)谴返,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任咧织,我火速辦了婚禮嗓袱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘习绢。我一直安慰自己渠抹,他們只是感情好败去,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赊时,像睡著了一般。 火紅的嫁衣襯著肌膚如雪行拢。 梳的紋絲不亂的頭發(fā)上祖秒,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天沼瘫,我揣著相機(jī)與錄音晕鹊,去河邊找鬼松却。 笑死砚哆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匈织,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吭露!你這毒婦竟也來(lái)了吠撮?” 一聲冷哼從身側(cè)響起讲竿,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤泥兰,失蹤者是張志新(化名)和其女友劉穎弄屡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鞋诗,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡膀捷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了师脂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片担孔。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖吃警,靈堂內(nèi)的尸體忽然破棺而出糕篇,到底是詐尸還是另有隱情,我是刑警寧澤酌心,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布拌消,位于F島的核電站,受9級(jí)特大地震影響安券,放射性物質(zhì)發(fā)生泄漏墩崩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一侯勉、第九天 我趴在偏房一處隱蔽的房頂上張望鹦筹。 院中可真熱鬧,春花似錦址貌、人聲如沸铐拐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)遍蟋。三九已至,卻和暖如春螟凭,著一層夾襖步出監(jiān)牢的瞬間虚青,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工螺男, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棒厘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓下隧,卻偏偏與公主長(zhǎng)得像奢人,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子汪拥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容