Spring 深入——IoC 容器 01

来源:https://www.cnblogs.com/cndada/archive/2022/10/09/16772905.html
-Advertisement-
Play Games

IoC容器的實現學習——01 簡介 在以前通常情況下一個簡單的項目一般由兩個及兩個以上的類構成,大多數的類集數據和數據的處理方法於一體,類之間通過依賴彼此的數據和方法實現業務邏輯,這個獲取依賴的過程是自己實現的,導致代碼高度耦合以及難以測試。 所以出現了DI (依賴註入)、IoC (控制反轉) 這些 ...


IoC容器的實現學習——01

目錄

簡介

在以前通常情況下一個簡單的項目一般由兩個及兩個以上的類構成,大多數的類集數據和數據的處理方法於一體,類之間通過依賴彼此的數據和方法實現業務邏輯,這個獲取依賴的過程是自己實現的,導致代碼高度耦合以及難以測試。

所以出現了DI (依賴註入)、IoC (控制反轉) 這些將對象的依賴關係轉交給平臺或容器進行管理的設計模式,而在 Spring 核心中 IoC 容器就是這種模式的實現。通過將對象的依賴控制交給 IoC 容器從而有效降低代碼的耦合度,提高代碼的可測試性。

IoC 容器需要解決的核心問題是如何將對象的控制權從對象轉交給平臺或框架中。

IoC 核心思想是關於一個對象如何獲取它所依賴的對象引用。

這次除了對 IoC 的簡單回顧,還有對 Spring 框架實現的 IoC 容器進行設計和實現上的分析,深入瞭解一下 Spring IoC 獨特的特點。

IoC 容器系列的設計與實現:BeanFactory 和 ApplicationContext

BeanFactory 介面系列:只實現了容器的基本功能。

ApplicationContext 應用上下文系列:在簡單容器的基礎上增加了許多面向框架的特性,同時對不同的應用場景進行了適配。

下麵對其兩者進行逐一分析。

BeanFactory

基本概念:BeanFactory 介面定義了一個 IoC 容器所應該具備的最基本服務,同時也是我們使用 IoC 容器遵守的最底層和最基本的編程規範。

同時有許多的類實現了 BeanFactory 這個基本介面,併在其基礎上進行了適當的擴展形成了具體的 IoC 容器,以針對不同的場景供用戶選擇,其中 ApplicationContext 也是在其基礎上構造的。

BeanFactory 介面的源碼:

image-20221007162938864

這些規範,體現了 IoC 容器最基本的特性。

其中主要的方法就是 getBean() 方法,還有一些其他的檢索方法,是最為基本的容器入口。

可以通過分析一個基本的 IoC 容器—— XmlBeanFactory 實現,來嘗試理解簡單 IoC 容器的設計原理。

image-20221008102922383

XmlBeanFactory 使用了 DefaultListableBeanFactory 作為基類,兩者作為基本的 IoC 容器,通過觀察 XBF 這個類名,可以猜到大概是通過 XML 文件來解析 BeanDefinition,並初始化 IoC 容器(事實也是如此)。

可以看到有一個常量,XmlBeanDefinitionReader 這個類是用來解析處理以 XML 形式定義的 BeanDefinition,是 Reader 對象,但是並不是它來獲取 XML 資源,XML 資源是交由另一個對象(Resource)來獲取並抽象的。Resource 是 Spring 用來封裝 I/O 操作的類(稱為定位 BeanDefinition 資源),例如 ClassPathResource 這個類可以指定獲取到具體的資源,並且將 Resuorce 交由 XBF 的構造函數,這樣 IoC 容器就可以方便的定位到需要的 BeanDefinition 信息對 Bean 完成容器的初始化和 DI 過程。

可能思路還不是很清晰,接下來就簡單解釋一下一些類:

  • BeanDefinition:

    這個類是 Spring 為了方便 IoC 容器管理 POJO (Bean) 對象而對其進一步抽象的數據結構,根據資源所定義的信息來創建具體的 Bean 對象。

    假設我們通過 XML 的形式來讓 IoC 容器幫我們管理 Bean 對象,其實我們在 XML 中定義的是 BeanDefinition,我們通過 <bean/> 標簽來創建 Bean,實際上是在描述一個 BeanDefinition,而當 IoC 容器通過 Reader 定位到 需要的 BeanDefinitieon,則是根據 Reader 解析好的 BeanDefinition 信息來創建我們描述好的 Bean 對象,併進行管理。

  • BeanDefinitionReader:

    讀取 Spring 配置文件中的內容,並將其轉換為 IoC 容器的內部數據結構:BeanDefinition。

    在 XBF 中 XBDR 就是 BDR 的一個具體實現,Spring 的配置內容是 XML,所以根據 XML 的形式來轉換 BeanDefinition。

  • Resource:

    Spring 統一對不同來源的資源進行底層抽象,方便統一管理不同的資源。

    通過簡單的觀察繼承關係和部分源碼,大概分析是 Spring 對不同來源的資源統一進行底層資源封裝或抽象。

    再通過不同的實現類對具體的資源面向用戶提高具體的服務介面。

通過解釋或者百度幾個關鍵類,我們應該能理解 IoC 容器初始化的簡單過程。

觀察 XBF 的源碼可以發現除了使用 XBDR 對象進行資源的解析和載入,並沒有看到關於 IoC 容器的初始化過程,看到 super(parentBeanFactory) 這句代碼調用了父類 —— DefaultListableBeanFactory 的構造方法,從而完成了 IoC 容器的構建。那麼我們初步可以分析出 DefaultListableBeanFactory 應該是 XBF IoC 容器創建的重要對象。實際上它也是個基本 IoC 容器。

直到這裡我們就簡單分析出了 XBF IoC 容器的創建過程。

loadBeanDefinition()

通過 reader 解析好的 Bean 信息載入到 BeanFactory (IoC 容器)中。

ApplicationContext

對於開發人員來說,例如開發一個 Web 服務端,如果要開發人員手動控制 Bean 的配置和容器的建立過程,無疑是非常痛苦的,所以 Spring 幫我們定義了許多已經實現好的容器,並且這些容器面向的需求也不一樣,相對於已經實現的簡單 BeanFactory 容器,不能很大程度上滿足開發人員的需求,所以 ApplicationContext 無疑是更好的選擇。

之前介紹了 ApplicationContext 是在基本 IoC 容器上,進行了更大程度的擴展,讓 IoC 容器面向框架,提供更多的服務,方便開發人員的使用,更加專註於業務邏輯的實現。同時也是對 IoC 容器一次全面的更新和擴展。

AC 擴展了一些介面,在基礎 IoC 容器上添加了附加功能,這些額外的功能為 AC 提供了 BeanFactory 不具備的特性:

  • 支持不同的信息源:擴展了 MessageSource 介面,支持國際化,為開發多語言版本的應用提供服務。

  • 訪問資源:主要體現在對 ResourceLoader 和 Resource 的支持上,讓我們可以獲從不同的地方獲取 Bean 資源,主要是可以在不同的 I/O 途徑獲取 Bean 定義信息。這裡的指的是具體的 ApplicationContext 容器,一般來說都是繼承了 DefaultResourceLoader 的子類,因為 DefaultResourceLoader 是 AbstractApplicationContext 的基類。

  • 支持應用事件

    繼承了介面 ApplicationEventPublisher,從而在上下文中引入了事件機制,這些事件結合 Bean 的生命周期對 Bean 管理提供了便利。

  • 提供其他附加服務

    這些其他的附加服務,使得基本的 IoC 的功能更加豐富,使它的使用是一種面向框架 的使用風格。

設計原理:

以常用的 FileSystemXmlApplicationContext 的實現為例說明 ApplicationContext 容器的設計原理。

通過觀察 FSXAC 的源碼,AC 容器的主要功能已經在 FSXAC 的基類 AbstractXmlApplicationContext 中實現了,所以 FSXAC 只要實現與自身設計相關的兩個功能。

功能一:如果直接使用 FSXAC,對於實例化這個應用上下文的支持,同時啟動 IoC 容器的 refresh() 過程。

refresh() 過程牽涉到 IoC 容器啟動的一系列複雜操作,對於不同的容器,這些操作都是類似的,因此在基類(AbstractApplicationContext)中對其統一封裝。

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
    super(parent);
    this.setConfigLocations(configLocations);
    if (refresh) {
        this.refresh();
    }
}

功能二: 如何從文件系統中載入 XML 的 Bean 定義資源有關。

簡單來說就是如何在文件系統中讀取以 XML 形式存在的 BeanDefinition 做準備(並不是直接解析),因為不同的 AC 實現對應著不同的讀取 BeanDefinition 的方式。

protected Resource getResourceByPath(String path) {
    if (path != null && path.startsWith("/")) {
        path = path.substring(1);
    }

    return new FileSystemResource(path);
}

上面是這個功能的實現,可以看到,調用這個方法可以得到 Resource 資源定位——FileSystemResource

小結

本次學習了 IoC 容器的一些介紹和概念,抓住了在 Spring 中 IoC 容器的兩大實現方式:BeanFactory 和 ApplicationContext.

藉助常用或典型的實現類:XmlBeanFactoryFileSystemApplicationContext

通過簡單分析兩者的實現和設計區別,來嘗試理解兩者本質或定義上的區別,同時我們也在兩者的實現和設計中,學到了 Spring IoC 容器中基礎的組成部分:

  • BeanDefinition
  • BeanDefinitionReader
  • Resource
  • DefaultListableBeanFactory
  • loadBeanDefinitions() 方法

這些與 IoC 容器密切相關。


在平時的 Spring 學習和使用中,我們大部分都僅限於使用,有時候項目報錯,即使百度,也會出現不能快速定位或者解決了但是又沒完全解決(不理解)的情況。

除了收集我們的日常 BUG 外,我們還需要對其淺層原理進行理解。我想這應該是逃離“碼農”的一小步。

努力地靠近自己理解的正軌。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 上次說了一下Go語言佈道師 Dave Cheney對Go併發的建議,個人覺得最重要的一條,這次主要想說一下這個。 8.3. Never start a goroutine without knowning when it will stop(永遠不要在不知道何時停止的情況下啟動 goroutine) ...
  • Future模式 【1】Future模式是多線程開發中常見的設計模式,它的核心思想是非同步調用。對於Future模式來說,它無法立即返回你需要的數據,但是它會返回一個契約,將來你可以憑藉這個契約去獲取你需要的信息。 【2】通俗一點就是生產者-消費者模型的擴展。經典“生產者-消費者”模型中消息的生產者不 ...
  • stream是java8新出的抽象概念,他可以讓你根據你期望的方式來處理集合數據,能夠輕鬆的執行複雜的查找、過濾和映射數據等操作。Stream 使用一種類似用 SQL 語句從資料庫查詢數據的直觀方式來提供一種對 Java 集合運算和表達的高階抽象。 ...
  • 數據結構基礎—棧和隊列 一、棧和隊列的基本概念和性質 棧和隊列都是特殊的線性表 對他們的操作有著規定和限制:在插入和刪除時只能對某一端操作 棧:只能在一端進行(先進後出) 隊列:只能在表尾插入,在表頭刪除(先進先出) 二、棧 表頭為棧底,表尾為棧頂 1.棧的基本操作和規則 a.進棧和出棧 進棧:棧頂 ...
  • 垃圾回收器 垃圾回收是釋放掉那些不再被使用的記憶體空間的過程。 換句話說,垃圾回收器會去檢查哪些對象超出範圍並且不會再被引用到,然後它回去釋放掉那些對象占用的記憶體空間。這個過程實在 go 程式運行中以併發的方式去進行的,不是 go 程式執行之前,也不是 go 程式執行之後。go 垃圾回收器實現的說明文 ...
  • 前幾天看報道說: 一位小哥用AI繪畫工具Midjourney生成的作品,在美國科羅拉多州博覽會的藝術比賽中獲得了第一名。 作者表示,他多次調整了輸入的提示詞,生成了100多幅畫作,經過數周的修改和挑選,才選出了三幅最滿意的作品。 下圖就是獲獎作品 之前我玩過DF,還寫過一篇文章➡️AI繪畫 Disc ...
  • python 有許多可視化工具,但本書只介紹Matplotlib。Matplotlib是一種2D的繪圖庫,它可以支持硬拷貝和跨系統的交互,它可以在python腳本,IPython的交互環境下、Web應用程式中使用。該項目是由John Hunter 於2002年啟動,其目的是為python構建MATL ...
  • STL和c++標準庫 標準模板庫STL部分包含在C++標準庫中的軟體庫。 c++標準庫:即以std::開頭,但是部分編譯器廠商也會把STL的內容放在std:: namespace裡面 由於一個常見的誤解,您可能會將C++標準庫視為“STL”,或者將工具鏈中C++標準庫的實現部分視為“STL實現”。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...