首先我們先來看看如下一段代碼
ClassPathResource resource = new ClassPathResource("bean.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(resource);
博友是否對這段簡單代碼記憶猶新呢? 這段代碼是編程式使用IOC容器,通過這個簡單的程序我們初步判定IOC容器的使用過程:
1、創建IOC配置文件的抽閑資源,也就是Resource接口。
2、創建BeanFactory,DefaultListtableBeanFactory是BeanFactory模式實現類。
3、創建一個BeanDefinitionReader對象,該對象為BeanDefinition的讀取器。xml文件就使用XMLBeanDefinitionReader。
4、使用Reader來裝載配置文件。loadBeanDefinitions就包括了資源文件的解析和注入過程。
通過上面四個步驟我們就可以輕松地使用IOC容器了,在整個過程可以剖析為三個步驟,這三個步驟也是IOC容器的初始化過程:Resource定位、載入、注冊。如下:
Resource定位
我們一般使用外部資源來描述Bean對象,所以IOC容器第一步就是需要定位Resource外部資源。Resource的定位其實就是BeanDefinition的資源定位,它是由ResourceLoader通過統一的Resource接口來完成的,這個Resource對各種形式的BeanDefinition的使用都提供了統一接口。
載入
第二個過程就是BeanDefinition的載入。BeanDefinitionReader讀取、解析Resource定位的資源,也就是將用戶定義好的Bean表示成IOC容器的內部數據結構也就是BeanDefinition。在IOC容器內部維護着一個BeanDefinition Map的數據結構,通過這樣的數據結構,IOC容器能夠對Bean進行更好的管理。
在配置文件中每一個<bean>都對應着一個BeanDefinition對象。
注冊
第三個過程則是注冊,即向IOC容器注冊這些BeanDefinition,這個過程是通過BeanDefinitionRegistery接口來實現的。在IOC容器內部其實是將第二個過程解析得到的BeanDefinition注入到一個HashMap容器中,IOC容器就是通過這個HashMap來維護這些BeanDefinition的。在這里需要注意的一點是這個過程並沒有完成依賴注入,依賴注冊是發生在應用第一次調用getBean向容器所要Bean時。當然我們可以通過設置預處理,即對某個Bean設置lazyinit屬性,那么這個Bean的依賴注入就會在容器初始化的時候完成。
經過這三個步驟,IOC容器的初始化過程就已經完成了,后面LZ會結合源代碼詳細闡述這三個過程的實現。下面來看看與IOC容器相關的體系結構圖,以ClassPathXmlApplicationContext為例(圖片來自:【Spring】IOC核心源碼學習(二):容器初始化過程)
左邊黃色部分是 ApplicationContext 體系繼承結構,右邊是 BeanFactory 的結構體系。