三條路線告訴你如何掌握Spring IoC容器的核心原理

Java小鋪發表於2018-08-27

一、前言

前三篇已經從歷史的角度和大家一起探討了為什麼會有Spring,Spring的兩個核心概念:IoC和AOP的雛形,Spring的歷史變遷和如今的生態帝國。本節的主要目的就是通過一個切入點帶大家一起學習一下Spring IoC的核心原理,正如從歷史的角度出發講述為什麼會有Spring一樣,希望通過這個切入點能讓你輕鬆的掌握住Spring IoC的核心原理。

本篇文章假設你已經可以熟練的使用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條基本路線,這樣的話逐步擊破,才能使自己不會被龐大的程式碼結構體系所嚇到!

在這裡順便給大家推薦一個架構交流群:617434785,裡面會分享一些資深架構師錄製的視訊錄影:有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能優化這些成為架構師必備的知識體系。

相關文章