Spring技術(shù)內(nèi)幕(一):IOC容器

原理:依賴反轉(zhuǎn)模式

合作對象的引用或依賴關(guān)系的管理交由容器或平臺來完成,而不是具體的對象。


IOC容器接口體系

IOC容器接口設(shè)計圖.png
  • 實現(xiàn)BeanFactory接口的簡單容器系列:實現(xiàn)了容器的最基本的功能
  • ApplicationContext應(yīng)用上下文:容器的高級特性

BeanFactory容器設(shè)計原理(以XmlBeanFactory實現(xiàn)為例)

public class XmlBeanFactory extends DefaultListableBeanFactory {

    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }

    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader.loadBeanDefinitions(resource);
    }
}
  • XmlBeanFactory繼承DefaultListableBeanFactory容器(默認(rèn)功能完整的IOC容器)
  • 通過XmlBeanDefinitionReader添加新功能

編程式使用IOC容器

注意觀察IOC容器實現(xiàn)中的那些關(guān)鍵的類(Resource,DefaultListableBeanFactory和 BeanDenifitionReader)之間的相互關(guān)系。如何把IOC容器功能解耦,又如何結(jié)合在一起為IOC容器服務(wù)。以下代碼都有注釋:

/**
     * Created by 阿越.
     * 以編程的方式使用DefaultListableBeanFactory
     */
    public void testSpringIOC(){
        // 創(chuàng)建IOC配置文件抽象資源(含有BeanDefinition)
        ClassPathResource resource = new ClassPathResource("beans.xml");
        // 創(chuàng)建一個BeanFactory
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        // 載入BeanDenifition的讀取器
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        // 讀入配置信息
        reader.loadBeanDefinitions(resource);
    }

ApplicationContext容器設(shè)計原理

(以FileSystemXmlApplicationContext實現(xiàn)為例)

// 實例化這個應(yīng)用上下文支持,啟動IOC容器的refresh()
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

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

// 從文件系統(tǒng)中加載XML的Bean定義資源
@Override
    protected Resource getResourceByPath(String path) {
        if (path != null && path.startsWith("/")) {
            path = path.substring(1);
        }
        return new FileSystemResource(path);
    }
  • 與BeanFactory容器的設(shè)計原理相似,先以繼承或構(gòu)造方法的形式實現(xiàn)父類功能,在此基礎(chǔ)上,添加自己的新功能。

IOC容器的初始化過程

  1. Resource定位:BeanDefinition的資源定位
  2. BeanDefinition的載入:把用戶定義好的Bean表示成IOC容器內(nèi)部數(shù)據(jù)結(jié)構(gòu)BeanDefinition
  3. 向IOC容器注冊BeanDefinition:把BeanDefinition注入到IOC內(nèi)部的一個HashMap中
Bean定義的載入和依賴注入是兩個獨立的過程
  • Bean定義(BeanDefinition)的載入是在IOC容器初始化時完成
  • 依賴注入默認(rèn)是在開發(fā)者第一次通過getBean向容器索取Bean的時完成
  • 設(shè)置lazyinit屬性,使該Bean的依賴注入在IOC容器初始化時就預(yù)先完成
refresh():IOC容器初始化入口,載入BeanDefinition的入口

以FileSystemXmlApplicationContext為例

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

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            // IOC容器初始化入口   
            refresh();
        }
    }

之后過程圖解如下(感興趣的可以照著圖看源碼):


BeanDefinition載入的交互過程.png
BeanDefinition在IOC容器中的注冊

在DefaultListableBeanFactory實現(xiàn)BeanDefinitionRegistry接口,這個接口的實現(xiàn)完成BeanDefinition向容器的注冊。具體實現(xiàn)可看源碼。


IOC容器的依賴注入

getBean接口的實現(xiàn)觸發(fā)依賴注入,是起點,內(nèi)部用doGetBean()實現(xiàn),之后會調(diào)用createBean。圖解如下:


依賴注入過程.png

參考資料:Spring技術(shù)內(nèi)幕(第2版) 計文柯

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

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

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