原理:依賴反轉(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容器的初始化過程
- Resource定位:BeanDefinition的資源定位
- BeanDefinition的載入:把用戶定義好的Bean表示成IOC容器內(nèi)部數(shù)據(jù)結(jié)構(gòu)BeanDefinition
- 向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