標籤:aop 描述 message init 路徑載入 inject 之間 體繫結構 進階服務
【原文】
Spring的兩個核心概念:IoC和AOP的雛形,Spring的曆史變遷和如今的生態帝國。
IoC和DI的基本概念
IoC(控制反轉,英文含義:Inverse of Control)是Spring容器的核心,AOP、事務等功能都是建立在此基礎上的。從字面意思上可以把IoC拆分為兩層含義:控制和反轉。控制可以理解為是介面實作類別的選擇權,反轉可以理解為這個選擇權交給第三方進行管理;總的來說就是某一介面具體實作類別的選擇控制權從調用類中移除,轉交給第三方進行決定,即由Spring容器通過Bean配置來進行控制,這樣的話應用程式本身就不用負責依賴對象的建立和維護,而由Spring容器進行管理。
儘管我們現在對IoC的基本概念都已經熟讀與心了,但是在老一輩的時候,IoC的概念還不是很容易被人理解。在那個年代,業界的一位大佬,軟體界泰鬥級的人物Martin Fowler提出了DI(Dependency Injection,依賴注入)的概念,來代替IoC。
依賴注入的概念和控制反轉的概念從本質上是一樣的,只是從不同的側面描述了這個功能。依賴注入的概念描述的是讓調用類對某一介面實作類別的依賴關係有第三方容器或其他東西注入,以此來移除對某一介面實作類別的依賴。
時至今日,我們常說的IoC/DI的時候也是把依賴注入和控制反轉作為同一個概念來進行闡述的!
三、從哪裡入手IoC容器?
我曾嘗試過很多次,想踏進Spring原理的大門,但是一次次都被毫無頭緒的開端而打退!後來逐漸翻閱一些書籍逐漸形成了那麼一點點思路,接下來主要按著我的思路探討一下Ioc容器的基本原理。
正如我們學習騎單車一樣,開始的時候都是先看別人如何騎的,然後自己才能慢慢的學會(當然發明單車的人是天才)。學習Spring原理也是一樣,只有掌握了基本的Spring的使用,才有可能踏進Spring原理的大門。因此,這裡我們從如何使用開始哪?
1、首先看一下項目結構
繼承關係:
bean的配置:
Main代碼如下:
2、相信每一個學習Spring的小夥伴都是從上述的方式學起的,中最顯眼的兩個類就是紅色圈圈出的,也設定我們在最開始使用到的,使用UML工具顯示最基本的類圖關係:
龐大的一個繼承和實現體系!看到這裡大致上也就是我要說的第二條路線了(下文會詳細介紹)!這條路線向我們展示了從Spring最接近用開發人員使用的ClassPathXmlApplicationContext、FileSystemXmlApplicationContext類到Spring的頂層介面之間層層的繼承和實現關係。
看到這裡我們似乎還是毫無頭緒,這就需要我們借鑒前人的經驗了,這個經驗就是如何正確的理解BeanFactory和ApplicationContext之間的關係。
四、BeanFactory和ApplicationContext之間的關係
我們都知道Spring是通過設定檔、註解、Java類等方式描述Bean與Bean之間的依賴關係,利用Java的反射功能執行個體化Bean並建立Bean與Bean之間的依賴關係;
這些底層的工作正是由Spring IoC容器完成的,除此之外Spring IoC容器還提供了Bean執行個體緩衝、生命週期管理、時間發布等進階服務。
而這裡要說的BeanFactory和ApplicationContext都作為Spring IoC容器的形態存在,只不過有些許區別而已,簡單的來說:(1)BeanFactory介面的實作類別是一個簡單容器系列,該系列的容器只實現了容器最基本的功能;(2)ApplicationContext介面的實作類別是一個進階容器系列,該系列的容器在簡單容器的基礎上增加了很多面向架構的特性,對應用環境做了很多適配,同時添加了很多面嚮應用的功能,例如:國際化支援和架構事件體繫結構等。
通常情況下,我們習慣稱BeanFactory為Ioc容器,而稱ApplicationContext為應用上下文,有時候我們還直接稱ApplicationContext為Spring容器。
至此,我應該可以引出我要說的前兩條路線:第一條路線是基於BeanFactory的簡單容器系列;第二天路線是基於ApplicationContext的進階容器系列;
五、第一條路線:基於BeanFactory的簡單容器系列
既然BeanFactory的實作類別也是一個容器,那麼我們就應該可以使用它來注入我們的Bean和擷取我們的Bean,如何使用哪?請看代碼:
(1)建立IoC設定檔的抽象資源,這個抽象資源套件含了BeanDefinition的定義資訊(也就是我們在bean.xml檔案中配置的一個bean的資料結構);
(2)建立一個BeanFactory,這裡使用的是DefaultListableBeanFactory;
(3)建立一個載入BeanDefinition的讀取器,這裡使用的是XmlBeanDefinitionReader來載入XML形式的BeanDefinition,通過一個回調配置給BeanFactory;
(4)從定義好的資源位置讀入配置資訊,具體的解析過程由XmlBeanDefinitionReader來完成。
上述的過程,完成了整個載入和註冊Bean的定義之後,我們所需要的IoC容器就建立起來了,這個時候我們就可以直接使用IoC容器了。
上述代碼中使用了DefaultListableBeanFactory 這個BeanFactory預設實現的容器完成了Bean的注入和擷取操作,查看其繼承和實現關係如下:
BeanFactory位於介面類結構的頂端,它主要定義了IoC容器中應該具有的基本特性,主要介面定義如下,根據名稱就可以看出是什麼作用,這裡不再一一解釋:
面對如此多的介面或類,我們應該如何理解哪?舉個栗子,就像一輛汽車一樣,BeanFactory中定義了這輛汽車應該具有的準系統,通過層層的介面繼承和實現為這個基本的汽車架構定製了很多特性,比如:可以座幾個人,是否可以倒車等,一直到最後才形成了一輛基本可以正常使用的汽車,但到這一步還是一個比較粗糙的產品或者半成品。(可以使用,但對於普通使用者不會直接使用)
而關於這些介面或類的介紹,由於篇幅有限,這裡不再一一介紹,主要給大家提供一種思路,如何順藤摸瓜,掌握第一條理解Spring IoC容器的路線。
總的來說,BeanFactory是Spring架構的基礎設定,面向的是Spring本身,下文中講述的第二條路線其中也是使用到了上述代碼中的過程,我們在實際的開發中很少會直接使用基於BeanFactory的簡單容器系列。
六、第二條路線:基於ApplicationContext的進階容器系列
相對於第一條路線中的汽車半成品來說,第二個路線下的產品才真正算是一輛可以開的出去的汽車,在基於ApplicationContext的進階容器系列下為汽車新增了很多特性,比如:加了電子檔位、加了倒車雷達、全景天窗、全液晶顯示器什麼的,一直到最後才形成了一輛可以使用的汽車(可以使用,普通使用者也可以直接使用)。
從中可以看出來,相對於BeanFactory來說ApplicationContext增加了很多新特性,例如MessageSource介面、ApplicationEventPublisher介面等,所以說ApplicationContext是一個進階形態意義上的IoC容器。
ApplicationContext的主要實作類別是ClassPathXmlApplicationContext、FileSystemXmlApplicationContext,前者是通過從類路徑載入設定檔,後者模式從檔案系統中裝載配置。
七、第三條路線:基於WebApplicationContext的Web容器系列
從上邊的介紹我們應該已經看出來了,不管是第一條路線還是第二條路線都是基於Java應用的,而我們使用最多的是JavaWeb應用,這也是接下來要說的第三條路線:基於WebApplicationContext的Web容器系列。
WebApplicationContext是專門為Web應用準備的,由於Web應用比一般的Java應用擁有更多的特性,因此WebApplicationContext擴充了ApplicationContext。
我們在配置Spring整合Spring MVC的時候基本都會使用上述的方式配置Spring容器,ContextLoaderListener通過Web容器上下文參數contextConfigLocation擷取Spring設定檔的位置。如果只是使用Xml配置的Bean的話,會使用WebApplicationContext的實作類別XmlWebApplicationContext。
八、總結
本文的目的並不是詳細的闡述Spring IoC容器的核心原理,這是因為市面上已經有很多書講述Spring IoC容器的核心原理的,並且簡單的一篇文章很難說清楚這麼多的內容,這裡主要是是希望通過將Spring IoC容器的核心原理內容進行劃分,整理為3條基本路線,這樣的話逐步擊破,才能使自己不會被龐大的代碼結構體系所嚇到!
【轉】Spring學習---Spring IoC容器的核心原理