1. 程式人生 > >spring IOC原始碼分析(1)

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原始碼分析1java.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