資深架構師帶你詳細瞭解,Spring之IoC容器
一、 IoC概述
IoC(Inverse of Control,控制反轉)是Spring容器的核心,AOP、宣告式事務等功能在此基礎上開花結構。不過IoC確實包括很多內涵,涉及程式碼解耦、設計模式、程式碼優化等問題的考量。
先來講下如下場景:
《墨攻》中有個場景,劉德華飾演的墨者革離來到樑國城下,樑國守衛問道:“來者何人?”劉德華回答:“墨者革離”。
有如下幾種程式碼實現方式:
其實可以這麼理解:飾演革離人物角色的,有多種選擇,不一定是劉德華,這個控制權掌握在導演手裡,所以最終的圖示關係就是如下圖:
那到底是什麼東西的“控制”被“反轉”了呢?對應到前面的例子,“控制”是指選擇GeLi角色扮演者的控制權;“反轉”是指這種控制權從《墨攻》劇本中移除,轉交到導演受眾。對於軟體來說,即某一介面具體實現類的選擇控制權從呼叫類中移除,轉交到第三方決定,即由Spring容器藉由Bean配置來進行控制。
控制反轉還是比較晦澀難懂,那麼軟體界的泰斗級人物Martin Fowler提出了DI(Dependency Injection,依賴注入)的概念來代替IoC。
1.1 IoC的型別
1. 建構函式注入
2. 屬性注入
3. 介面注入
1.2 通過容器完成依賴關係的注入
所謂媒體“海選”和第三方代理機構,在程式領域就是一個第三方的容器,他幫助完成類的初始化與裝配工作,讓開發者從這些底層實現類的例項化、依賴關係裝配等工作中解脫出來,專注於更有意義的業務邏輯開發工作。這無疑是一件令人嚮往的事情。Spring就是這樣的一個容器,它通過配置檔案或註解描述類和類之間的依賴關係,自動完成類的初始化和依賴注入工作。
二、 相關Java基礎知識
Java語言允許通過程式化的方式間接對Class進行操作。Class檔案由類裝載器裝載後,在JVM中獎形成一份描述Class結構的元資訊物件,通過該元資訊物件可以獲知Class的結構資訊,如建構函式、屬性和方法等。Java允許使用者藉由這個與Class相關的元資訊物件間接呼叫Class物件的功能,這就為使用程式化方式操作Class物件開闢了途徑。
2.1 類裝載器 ClassLoader
1. 類裝載器的工作機制
類裝載器把一個類裝入JVM中,需要經過一下步驟:
(1)裝載:查詢和匯入Class檔案
(2)連結:執行校驗、準備和解析步驟,其中解析步驟是可以選擇的。
1. 校驗:檢查載入Class檔案資料的正確性。
2. 準備:給類的靜態變數分配儲存空間。
3. 解析:將符號引用轉換成直接引用。
(3)初始化:對類的靜態變數、靜態程式碼塊執行初始化工作。
2.2 Java反射機制
Java的反射體系保證了可以通過程式化的方式訪問目標類中的所有的元素,對於private或protexted成員變數和方法,只要JVM的安全機制允許,也可以通過反射進行呼叫。
架構師圈子:142019080
三、 資源抽象介面
JDK所提供的訪問資源的類(如 java.net.URL、FIle等)並不能很好的滿足各種底層資源的訪問需求,比如缺少從類路徑或者Web容器上下文獲取資源的操作類,鑑於此,Spring設計了一個Resource介面,它為應用提供了更強的底層資源訪問能力。
四、 BeanFactory 和 ApplicationContext
Spring 通過一個配置檔案描述Bean及Bean之間的依賴關係,利用Java語言的反射功能例項化Bean並建立Bean之間的依賴關係。Spirng的IoC容器在完成這些底層工作的基礎上,還提供了Bean例項快取、生命週期管理、Bean例項代理、事件釋出、資源裝載等高階服務。
我們一般稱BeanFactory為IoC容器,而稱ApplicationContext為應用上下文。但有時為了行文方便,我們也將ApplicationContext稱為Spring容器。
BeanFactory是Spring框架的基礎設施,面向Spring本身;ApplicaitonContext面向使用Spring框架的開發者,幾乎所有的應用場合都可以使用ApplicationContext而非底層的BeanFactory。
4.1. 初始化BeanFactory
1) 對於單例項的Bean來說,BeanFactory會快取Bean例項,所以第二次使用getBean()獲取Bean時,將直接從IoC容器的快取中獲取Bean例項。
2) 在Spring中,DefaultSingletonBeanRegistry類中提供了一個用於快取單例項Bean的快取器,它是一個用HashMap實現的快取器,單例項的Bean以beanName為鍵儲存在這個HashMap中。
3) 在初始化BeanFactory時,必須提供一種日誌框架
4.2 ApplicationContext介紹
如果說BeanFactory是Spring的“心臟”,那麼ApplicationContext就是完整的“身軀”了。
1. ApplicationContext類體系結構,它是一個介面,程式碼如下:
public interface ApplicationContext extends ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { String getId(); String getDisplayName(); long getStartupDate(); ApplicationContext getParent(); AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException; }
1)ApplicationEventPublisher: 讓容器擁有釋出應用上下文事件的功能,包括容器啟動事件、關閉事件。
2)MessageSource: 為應用提供i18n國際化訊息訪問的功能
3)ResourcePatternResolver: 所有ApplicationContext實現類都實現了類似於PathMatchingResourcePatternResolver的功能,可以通過帶字首的Ant風格的資原始檔路徑裝載Spring的配置檔案。
4)LifeCycle: 該介面提供了start()和stop()兩個方法,主要用於控制非同步處理過程。架構師圈子:142019080
初始化ApplicationContext的幾種方式:
1)如果配置檔案放置在類路徑下,則可以優先考慮使用ClassPathXmlApplicationContext實現類
2)如果配置檔案放置在檔案系統的路徑下,則可以優先考慮使用FileSystemXml
3)基於註解的配置方式如下:
4)基於Groovy DSL來配置Bean
2. WebApplicationContext類體系結構
在非Web應用的環境下,Bean只有singletom和prototype兩種作用域。WebApplicationContext為Bean添加了三個新的作用域:request、session和global session.
ConfigurableWebApplicationContext擴充套件了WebApplicationContext,它允許通過配置的方式例項化WebApplicationContext,同時定義了兩個重要的方法。
setServletContext(ServletContext context):為Spring設定Web應用上下文,以便二者整合。
setConfigLocations(String[] configLocation): 設定Spring配置檔案地址。
3. WebApplicationContext初始化
1)使用配置檔案
2)使用註解的方式
3)使用Groovy DSL的方式
4.3 父子容器
通過HierarchicalBeanFactory介面,Spring的IoC容器可以建立父子層級關聯的容器體系,子容器可以訪問如容器中的Bean,但是父容器不能訪問自容器中的Bean。
例如:Spring使用父子容器實現很多功能,比如在Spring MVC中,展現層Bean位於一個子容器中,而業務層和持久層Bean位於如容器中。這樣,展現層Bean就可以引用業務層和持久層Bean,而業務層和持久層Bean則看不到展現層Bean。
五、BeanFactory中的Bean的生命週期
Spring為Bean提供了細緻周全的生命週期過程,通過實現特定的介面或通過<bean>屬性設定,都可以對Bean的生命週期過程施加影響。Bean的生命週期不但和其實現的介面相關,還與Bean的作用範圍有關。為了讓Bean繫結在Spring框架上,我們推薦使用配置方式而非介面方式進行Bean生命週期的控制。
如果對java微服務、分散式、高併發、高可用、大型網際網路架構技術、面試經驗交流。
可以加我架構師圈子:142019080 領取資料,裡面每天更新資