一、什麼是Ioc/DI?
IoC 容器:最主要是完成了完成物件的建立和依賴的管理注入等等。先從我們自己設計這樣一個視角來考慮:所謂控制反轉,就是把原先我們程式碼裡面需要實現的物件建立、依賴的程式碼,反轉給容器來幫忙實現。那麼必然的我們需要建立一個容器,同時需要一種描述來讓容器知道需要建立的物件與物件的關係。這個描述最具體表現就是我們可配置的檔案。物件和物件關係怎麼表示?可以用 xml , properties 檔案等語義化配置檔案表示。描述物件關係的檔案存放在哪裡?可能是 classpath , filesystem ,或者是 URL 網路資源, servletContext 等。回到正題,有了配置檔案,還需要對配置檔案解析。不同的配置檔案對物件的描述不一樣,如標準的,自定義宣告式的,如何統一? 在內部需要有一個統一的關於物件的定義,所有外部的描述都必須轉化成統一的描述定義。
如何對不同的配置檔案進行解析?需要對不同的配置檔案語法,採用不同的解析器
二、 Spring IOC體系結構?
(1) BeanFactory
Spring Bean的建立是典型的工廠模式,這一系列的Bean工廠,也即IOC容器為開發者管理物件間的依賴關係提供了很多便利和基礎服務,在Spring中有許多的IOC容器的實現供使用者選擇和使用,其相互關係如下:
其中BeanFactory作為最頂層的一個介面類,它定義了IOC容器的基本功能規範,BeanFactory 有三個子類:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。但是從上圖中我們可以發現最終的預設實現類是 DefaultListableBeanFactory,他實現了所有的介面。那為何要定義這麼多層次的介面呢?查閱這些介面的原始碼和說明發現,每個介面都有他使用的場合,它主要是為了區分在 Spring 內部在操作過程中物件的傳遞和轉化過程中,對物件的資料訪問所做的限制。例如 ListableBeanFactory 介面表示這些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是這些 Bean 是有繼承關係的,也就是每個Bean 有可能有父 Bean。AutowireCapableBeanFactory 介面定義 Bean 的自動裝配規則。這四個介面共同定義了 Bean 的集合、Bean 之間的關係、以及 Bean 行為。最基本的IOC容器介面BeanFactory
public interface BeanFactory { //對FactoryBean的轉義定義,因為如果使用bean的名字檢索FactoryBean得到的物件是工廠生成的物件, //如果需要得到工廠本身,需要轉義 String FACTORY_BEAN_PREFIX = "&"; //根據bean的名字,獲取在IOC容器中得到bean例項 Object getBean(String name) throws BeansException; //根據bean的名字和Class型別來得到bean例項,增加了型別安全驗證機制。 Object getBean(String name, Class requiredType) throws BeansException; //提供對bean的檢索,看看是否在IOC容器有這個名字的bean boolean containsBean(String name); //根據bean名字得到bean例項,並同時判斷這個bean是不是單例 boolean isSingleton(String name) throws NoSuchBeanDefinitionException; //得到bean例項的Class型別 Class getType(String name) throws NoSuchBeanDefinitionException; //得到bean的別名,如果根據別名檢索,那麼其原名也會被檢索出來 String[] getAliases(String name); }
在BeanFactory裡只對IOC容器的基本行為作了定義,根本不關心你的bean是如何定義怎樣載入的。正如我們只關心工廠裡得到什麼的產品物件,至於工廠是怎麼生產這些物件的,這個基本的介面不關心。而要知道工廠是如何產生物件的,我們需要看具體的IOC容器實現,spring提供了許多IOC容器的實現。比如XmlBeanFactory,ClasspathXmlApplicationContext等。其中XmlBeanFactory就是針對最基本的ioc容器的實現,這個IOC容器可以讀取XML檔案定義的BeanDefinition(XML檔案中對bean的描述),如果說XmlBeanFactory是容器中的屌絲,ApplicationContext應該算容器中的高帥富。ApplicationContext是Spring提供的一個高階的IoC容器,它除了能夠提供IoC容器的基本功能外,還為使用者提供了以下的附加服務。從ApplicationContext介面的實現,我們看出其特點:
- 1. 支援資訊源,可以實現國際化。(實現MessageSource介面)
- 2. 訪問資源。(實現ResourcePatternResolver介面,這個後面要講)
- 3. 支援應用事件。(實現ApplicationEventPublisher介面)
(2) BeanDefinition
SpringIOC容器管理了我們定義的各種Bean物件及其相互的關係,Bean物件在Spring實現中是以BeanDefinition來描述的,其繼承體系如下:
Bean 的解析過程非常複雜,功能被分的很細,因為這裡需要被擴充套件的地方很多,必須保證有足夠的靈活性,以應對可能的變化。Bean 的解析主要就是對 Spring 配置檔案的解析。這個解析過程主要通過下圖中的類完成:
三、IoC容器的初始化?
IoC容器的初始化包括BeanDefinition的Resource定位、載入和註冊這三個基本的過程。我們以ApplicationContext為例講解,ApplicationContext系列容器也許是我們最熟悉的,因為web專案中使用的XmlWebApplicationContext就屬於這個繼承體系,還有ClasspathXmlApplicationContext等,其繼承體系如下圖所示:
ApplicationContext允許上下文巢狀,通過保持父上下文可以維持一個上下文體系。對於bean的查詢可以在這個上下文體系中發生,首先檢查當前上下文,其次是父上下文,逐級向上,這樣為不同的Spring應用提供了一個共享的bean定義環境。
下面我們分別簡單地演示一下兩種ioc容器的建立過程
1、XmlBeanFactory(屌絲IOC)的整個流程
通過XmlBeanFactory的原始碼,我們可以發現:
public class XmlBeanFactory extends DefaultListableBeanFactory{ private final XmlBeanDefinitionReader reader; public XmlBeanFactory(Resource resource)throws BeansException{ this(resource, null); } public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException{ super(parentBeanFactory); this.reader = new XmlBeanDefinitionReader(this); this.reader.loadBeanDefinitions(resource); } }
//根據Xml配置檔案建立Resource資源物件,該物件中包含了BeanDefinition的資訊 ClassPathResource resource =new ClassPathResource("application-context.xml"); //建立DefaultListableBeanFactory DefaultListableBeanFactory factory =new DefaultListableBeanFactory(); //建立XmlBeanDefinitionReader讀取器,用於載入BeanDefinition。之所以需要BeanFactory作為引數,是因為會將讀取的資訊回撥配置給factory XmlBeanDefinitionReader reader =new XmlBeanDefinitionReader(factory); //XmlBeanDefinitionReader執行載入BeanDefinition的方法,最後會完成Bean的載入和註冊。完成後Bean就成功的放置到IOC容器當中,以後我們就可以從中取得Bean來使用 reader.loadBeanDefinitions(resource);
參考部落格:https://www.cnblogs.com/ITtangtang/p/3978349.html#a1 https://zhuanlan.zhihu.com/p/32830470