再次閱讀這本書有些不一樣的感悟,記錄一些零星點點。
1.1 關於IOC容器設計的線路區別
我們都知道在Spring裡主要有兩種設計IOC容器的思路,一種是圍繞BeanFactory,另外一種是圍繞ApplicationContext展開。這兩種設計的主要區別在哪裡?
從頭回憶一下兩種設計方案的實現
1.1.1 BeanFactory
以下是BeanFactory介面:
處於IOC頂層的設計介面BeanFactory只提供了一些基本的方法,getBean(),containsBean(),isSingleton()等等。
我們以XmlBeanFactory為例子展示建立它的過程:
首先是一張UML圖:
建構函式:
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader = new XmlBeanDefinitionReader(this);
this.reader.loadBeanDefinitions(resource);
}
可以看出建立以BeanFactory為設計路線的IOC容器的時候主要有四步:
- 建立Rerouce資源類,定位到xml。
- 建立BeanFactory類。
- 建立Reader類並回撥配置給我們建立的BeanFactory類。
- 用這個Reader類去載入我們的BeanDefinition
1.1.2 ApplicationContext
可以從類結構圖裡看到Application不僅繼承了我們傳統的BeanFactory設計線路,還繼承了其他介面,這樣使得ApplicationIOC容器的功能更加強大。有以下特點:
- 支援不同的資訊源
- 訪問資源,這一特性體現在我們的Resouce和ResourceReader上,這樣我們可以從不同的地方得到BeanDefinition
- 支援應用事件。這些事件和Bean生命週期的結合為管理Bean提供了便利。
關於Bean的載入和依賴注入其實兩個不同的過程,Bean的載入一般分為三個過程:1.BeanDefinition的定位2.Bean資訊的載入(將具體POJO物件抽象為Bean內部資料結構的過程)3.Bean資訊的註冊(IOC內部會維護一個hashmap去儲存這些Bean資訊)。而我們的依賴注入也就是我們所謂的DI,這裡注意關於IOC和DI你可以將IOC理解成一種設計手段,而DI就是實現這種手段的一種方式 。我們的DI一般發生在我們應用首次呼叫該Bean的時候。當然有一種例外在Bean初始化的時候就發生依賴注入就是我們的懶載入機制。
這裡結束就可以回答開頭的問題,這兩種設計路線的區別,從類結構圖可以看到ApplicationContext已經繼承了Reader類為我們提供了一系列載入不同Resource的讀取器的實現。因此我們程式設計式中就不必為該類IOC容器宣告Reader再進行回撥配置了。
2.1 FileSystemXmlApplicationContext
那麼ApplicationContext類IOC容器在何時配置的讀取器,我們以FileSystemXmlApplicationContext為例:
關於這個讀取器的配置我們可以在它的基類AbstractRefreshableApplicationContext中找到,我們都知道refresh的呼叫是在FileSystemXmlApplicationContext的建構函式中,這是IOC容器初始化的入口。在AbstractRefreshableApplicationContext中有一個抽象方法loadBeanDefinitions(DefaultListableBeanFactory var1),這個抽象方法在 AbstractXmlApplicationContext中有被實現其中就配置了Reader讀取器。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
this.initBeanDefinitionReader(beanDefinitionReader);
this.loadBeanDefinitions(beanDefinitionReader);
}