1.何謂Spring IOC
何謂Spring IOC?書上謂之“依賴注入”,那何謂“依賴注入”?
作爲一個Java程序猿,應該遇到過這樣的問題,當你在代碼中需要使用某個類提供的功能時,你首先需要new一個對象,給它傳遞必要的參數,然後才能使用它提供的功能,最後釋放對象佔用的內存,當然了這個在Java不需要你自己去幹了。這也就是說你需要自己去管理變量的整個生命週期,這在大型項目中是很糟糕的。現在好了,有了Spring IOC,這些事情都不需要你去做,你只需要告訴Spring你需要的變量實例,配置其對應關係,Spring就可以講你依賴的實例注入到你的變量中。
舉個現實的例子,在以前大家找對象都是自己去找,自己去處的,現在不一樣了,很多人都通過相親了,這就有了相親機構,其實這裏相親機構就是一個Spring IOC容器,你想要找對象,然後你就去找相親機構,在它那裏注個冊,告訴它你的要求,比如說高矮胖瘦等等,這個時候,相親機構就從已經在它那註冊了的所有女生中(注:這個時候,你跟那些女生都是相親機構管理的bean對象)找到符合你要求的女生,最後給到你,讓你們自己去折騰了……,這也就是所謂的“依賴注入”,也就是Spring IOC的精髓所在。
2 Spring IOC體系結構
Bean工廠
SpringBean的創建是典型的工廠模式,這一系列的Bean工廠,也即IOC容器爲開發者管理對象間的依賴關係提供了很多便利和基礎服務,在Spring中有許多的IOC容器的實現供用戶選擇和使用,其相互關係如下:
其中BeanFactory作爲最頂層的一個接口類,它定義了IOC容器的基本功能規範,BeanFactory 有三個子類:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。但是從上圖中我們可以發現最終的默認實現類是 DefaultListableBeanFactory,他實現了所有的接口。那爲何要定義這麼多層次的接口呢?查閱這些接口的源碼和說明發現,每個接口都有他使用的場合,它主要是爲了區分在 Spring 內部在操作過程中對象的傳遞和轉化過程中,對對象的數據訪問所做的限制。例如 ListableBeanFactory 接口表示這些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是這些 Bean 是有繼承關係的,也就是每個Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定義 Bean 的自動裝配規則。這四個接口共同定義了 Bean 的集合、Bean 之間的關係、以及 Bean 行爲。
Bean的表示
SpringIOC容器管理了我們定義的各種Bean對象及其相互的關係,Bean對象在Spring實現中是以BeanDefinition來描述的,其繼承體系如下:
Bean 的解析過程非常複雜,功能被分的很細,因爲這裏需要被擴展的地方很多,必須保證有足夠的靈活性,以應對可能的變化。Bean 的解析主要就是對 Spring 配置文件的解析。這個解析過程主要通過下圖中的類完成:
2. 最基本的IOC容器接口:
1. public interface BeanFactory {
2.
3. //這裏是對FactoryBean的轉義定義,因爲如果使用bean的名字檢索FactoryBean得到的對象是工廠生成的對象,
4. //如果需要得到工廠本身,需要轉義
5. String FACTORY_BEAN_PREFIX = "&";
6.
7.
8. //這裏根據bean的名字,在IOC容器中得到bean實例,這個IOC容器就是一個大的抽象工廠。
9. Object getBean(String name) throws BeansException;
10.
11. //這裏根據bean的名字和Class類型來得到bean實例,和上面的方法不同在於它會拋出異常:如果根據名字取得的bean實例的Class類型和需要的不同的話。
12. Object getBean(String name, Class requiredType) throws BeansException;
13.
14. //這裏提供對bean的檢索,看看是否在IOC容器有這個名字的bean
15. boolean containsBean(String name);
16.
17. //這裏根據bean名字得到bean實例,並同時判斷這個bean是不是單件
18. boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
19.
20. //這裏對得到bean實例的Class類型
21. Class getType(String name) throws NoSuchBeanDefinitionException;
22.
23. //這裏得到bean的別名,如果根據別名檢索,那麼其原名也會被檢索出來
24. String[] getAliases(String name);
25.
26. }
在BeanFactory裏只對IOC容器的基本行爲作了定義,根本不關心你的bean是如何定義怎樣加載的。正如我們只關心工廠裏得到什麼的產品對象,至於工廠是怎麼生產這些對象的,這個基本的接口不關心。
而要知道工廠是如何產生對象的,我們需要看具體的IOC容器實現,spring提供了許多IOC容器的實現。比如XmlBeanFactory,ClasspathXmlApplicationContext等。
3. IoC容器的初始化
IoC容器的初始化包括BeanDefinition的Resource定位、載入和註冊這三個基本的過程。我們以ApplicationContext爲例講解,ApplicationContext系列容器也許是我們最熟悉的,因爲web項目中使用的XmlWebApplicationContext就屬於這個繼承體系,還有ClasspathXmlApplicationContext等,其繼承體系如下圖所示:
ApplicationContext允許上下文嵌套,通過保持父上下文可以維持一個上下文體系。對於bean的查找可以在這個上下文體系中發生,首先檢查當前上下文,其次是父上下文,逐級向上,這樣爲不同的Spring應用提供了一個共享的bean定義環境。
從ApplicationContext接口的實現,我們看出其特點:
1. 支持信息源,可以實現國際化。(實現MessageSource接口)
2. 訪問資源。(實現ResourcePatternResolver接口,這個後面要講)
3. 支持應用事件。(實現ApplicationEventPublisher接口)
我們看ClassPathXmlApplicationContext是如何建立IOC容器,先看其構造函數:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
refresh的模板是在AbstractApplicationContext中:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
……
這裏是我們分析的入口,其完成了整個的bean初始化過程。