spring IOC原始碼分析(1)
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初始化過程。相關推薦
spring IOC原始碼分析(1)
1.何謂Spring IOC 何謂Spring IOC?書上謂之“依賴注入”,那何謂“依賴注入”? 作為一個Java程式猿,應該遇到過這樣的問題,當你在程式碼中需要使用某個類提供的功能時,你首先需要new一個物件,給它傳遞必要的引數,然後才
Spring Session 原始碼分析(1)——springSessionRepositoryFilter
#Tomcat Session 對於session 是一個老生暢談的話題了,Session管理是JavaEE容器比較重要的一部分, Tomcat中主要由每個context容器內的一個Manager物件來管理session。對於這個manager物件的實現,可以
spring4.2.9 java專案環境下ioc原始碼分析(三)——refresh之obtainFreshBeanFactory方法(@1準備工作與載入Resource)
obtainFreshBeanFactory方法從字面的意思看獲取新的Bean工廠,實際上這是一個過程,一個載入Xml資源並解析,根據解析結果組裝BeanDefinitions,然後初始化BeanFactory的過程。在載入Xml檔案之前,spring還做了一些其他的工作,比
Spring初始化過程原始碼分析(1)
本文主要詳細分析Spring初始化過程的原始碼分析,目的是理解Spring具體是如何工作的。部分內容查閱於網路,有不妥之處望指正。 1、web專案中伺服器一啟動就開始載入web.xml,Spring的啟動是從web.xml中的org.springframewo
Mybatis原始碼分析(1)—— Mapper檔案解析
感覺CSDN對markdown的支援不夠友好,總是伴隨各種問題,很惱火! xxMapper.xml的解析主要由XMLMapperBuilder類完成,parse方法來完成解析: public void parse() { if (!configuration.isRes
比特幣BTC原始碼分析(1):地址生成過程
一、生成一個比特幣錢地址 二、根據原始碼整理比特幣地址生成過程 1、取得公鑰PubKey 2、使用 RIPEMD160(SHA256(PubKey)) 雜湊演算法,取公鑰並對其雜湊兩次 3、給雜湊加上地址生成演算法版本的字首 4、對於第二步生成的結果,使用SHA256(SHA256
以太坊ETH原始碼分析(1):地址生成過程
一、生成一個以太坊錢包地址 通過以太坊命令列客戶端geth可以很簡單的獲得一個以太坊地址,如下: ~/go/src/github.com/ethereum/go-ethereum/build/bin$geth account new INFO [11-03|20:09:33.219]
jdk原始碼分析(1)java.lang.Object
java.lang.Object原始碼分析 public final native Class<?> getClass() public native int hashCode(); public boolean e
tensorflow原始碼分析(1)
variable類: 通過例項化Variable類可以新增一個變數到graph,在使用變數之前必須對變數顯示的初始化,初始化可以使用assign為變數賦值也可以通過變數本身的initializer方法。 &nb
ES5.6.2原始碼分析(1):準備工作
1、gradle安裝 下載4.5版本,解壓後配置環境變數即可。 注:gradle安裝完成後, 為了加快依賴檔案的下載需要在使用者目錄中新建init.gradle檔案(讓全域性可見,build時會用到)。檔案的具體內容為: 目錄:C:\Users\admin.gradle
tensorflowV1.11-原始碼分析(1)
##</Users/deepmyhaspl/docs/tensorflow-src/tensorflow-r1.11>####[4]|<====configure.py=====>|## # Copyright 2017 The TensorFlow Authors. All
Django rest framework原始碼分析(1)----認證
目錄 一、基礎 1.1.安裝 兩種方式: pip install djangorestframework 1.2.需要先了解的一些知識 理解下面兩個知識點非常重要,django-rest-framework原始碼中到處都是基於CBV和麵向物件的封裝 (1)面向物件封裝的兩大特性
Android6.0的Looper原始碼分析(1)
Android在Java標準執行緒模型的基礎上,提供了訊息驅動機制,用於多執行緒之間的通訊。而其具體實現就是Looper。 Android Looper的實現主要包括了3個概念:Message,MessageQueue,Handler,Looper。其中Message就是
libevent原始碼分析(1)
有過看nginx原始碼的基礎,現在來看libevent原始碼,感覺要輕鬆多了。。 第一篇文章,主要是還是介紹一些幾個重要的資料結構吧。。。。 首先是event結構:struct event { TAILQ_ENTRY (event) ev_next; //用於構成eve
Freescale i.MX6 Linux Ethernet Driver驅動原始碼分析(1)
最近需要在Freescale i.MX6上移植Ethernet AVB的核心patch,Ethernet AVB的Wiki:http://en.wikipedia.org/wiki/Audio_Video_Bridging,而Freescale原來已經在kernel 3.
spring4.2.9 java專案環境下ioc原始碼分析(四)——refresh之obtainFreshBeanFactory方法(@2處理Resource、載入Document及解析前準備)
接上篇文章,上篇文章講到載入完返回Rescouce。先找到要解析的程式碼位置,在AbstractBeanDefinitionReader類的loadBeanDefinitions(String location, Set<Resource> actualResou
Android系統原理與原始碼分析(1):利用Java反射技術阻止通過按鈕關閉對話方塊
本文為原創,如需轉載,請註明作者和出處,謝謝! 眾所周知,AlertDialog類用於顯示對話方塊。關於AlertDialog的基本用法在這裡就不詳細介紹了,網上有很多,讀者可以自己搜尋。那
spring4.2.9 java專案環境下ioc原始碼分析(六)——refresh之obtainFreshBeanFactory方法(@4預設標籤bean,beans解析、最終註冊)
接上篇文章,解析了import和alias標籤,只是開胃菜比較簡單,下面介紹bean標籤的載入,也是預設名稱空間下解析的重點。protected void processBeanDefinition(Element ele, BeanDefinitionParserDeleg
spring4.2.9 java專案環境下ioc原始碼分析(五)——refresh之obtainFreshBeanFactory方法(@3預設標籤import,alias解析)
接上篇文章,到了具體解析的時候了,具體的分為兩種情況,一種是預設名稱空間的標籤<bean>;另一種是自定義名稱空間的標籤比如<context:xxx>,<tx:xxx>等。先看下預設的名稱空間的標籤解析。protected void par
spring4.2.9 java專案環境下ioc原始碼分析(一)——執行refresh之前
本系列文章講述spring IOC容器如何載入Bean與例項化Bean以及其中所穿插的一些實現。本文章以ClassPathXmlApplicationContext為起點,debug啟動流程。程式碼如下public static void main(String[] args