Spring(2)——Spring IoC 詳解

来源:https://www.cnblogs.com/wmyskxz/archive/2018/04/13/8824597.html
-Advertisement-
Play Games

Spring IoC 概述 IoC:Inverse of Control(控制反轉) 讀作 “反轉控制” ,更好理解,不是什麼技術,而是一種 設計思想 ,就是 將原本在程式中手動創建對象的控制權,交由Spring框架來管理。 正控: 若要使用某個對象,需要 自己去負責對象的創建 反控: 若要使用某個 ...


Spring IoC 概述

IoC:Inverse of Control(控制反轉)

  • 讀作“反轉控制”,更好理解,不是什麼技術,而是一種設計思想,就是將原本在程式中手動創建對象的控制權,交由Spring框架來管理。
  • 正控:若要使用某個對象,需要自己去負責對象的創建
  • 反控:若要使用某個對象,只需要從 Spring 容器中獲取需要使用的對象,不關心對象的創建過程,也就是把創建對象的控制權反轉給了Spring框架
  • 好萊塢法則:Don’t call me ,I’ll call you

一個例子

控制反轉顯然是一個抽象的概念,我們舉一個鮮明的例子來說明。

在現實生活中,人們要用到一樣東西的時候,第一反應就是去找到這件東西,比如想喝新鮮橙汁,在沒有飲品店的日子里,最直觀的做法就是:買果汁機、買橙子,然後準備開水。值得註意的是:這些都是你自己“主動”創造的過程,也就是說一杯橙汁需要你自己創造。

然而到了今時今日,由於飲品店的盛行,當我們想喝橙汁時,第一想法就轉換成了找到飲品店的聯繫方式,通過電話等渠道描述你的需要、地址、聯繫方式等,下訂單等待,過一會兒就會有人送來橙汁了。

請註意你並沒有“主動”去創造橙汁,橙汁是由飲品店創造的,而不是你,然而也完全達到了你的要求,甚至比你創造的要好上那麼一些。

Spring IoC 闡述

這就是一種控制反轉的理念,上述的例子已經很好的說明瞭問題,我們再來描述一下控制反轉的概念:控制反轉是一種通過描述(在 Java 中可以是 XML 或者註解)並通過第三方(Spring)去產生或獲取特定對象的方式。

  • 好處:
    降低對象之間的耦合
    我們不需要理解一個類的具體實現,只需要知道它有什麼用就好了(直接向 IoC 容器拿)

主動創建的模式中,責任歸於開發者,而在被動的模式下,責任歸於 IoC 容器,基於這樣的被動形式,我們就說對象被控制反轉了。(也可以說是反轉了控制)


Spring IoC 容器

Spring 會提供 IoC 容器來管理和容納我們所開發的各種各樣的 Bean,並且我們可以從中獲取各種發佈在 Spring IoC 容器里的 Bean,並且通過描述可以得到它。

Spring IoC 容器的設計

Spring IoC 容器的設計主要是基於以下兩個介面:

  • BeanFactory
  • ApplicationContext

其中 ApplicationContext 是 BeanFactory 的子介面之一,換句話說:BeanFactory 是 Spring IoC 容器所定義的最底層介面,而 ApplicationContext 是其最高級介面之一,並對 BeanFactory 功能做了許多的擴展,所以在絕大部分的工作場景下,都會使用 ApplicationContext 作為 Spring IoC 容器。

ApplicationContext 繼承關係

BeanFactory

從上圖中我們可以幾乎看到, BeanFactory 位於設計的最底層,它提供了 Spring IoC 最底層的設計,為此,我們先來看看該類中提供了哪些方法:

由於這個介面的重要性,所以有必要在這裡作一下簡短的說明:

  • 【getBean】 對應了多個方法來獲取配置給 Spring IoC 容器的 Bean。
    ① 按照類型拿 bean:
    bean = (Bean) factory.getBean(Bean.class);
    註意:要求在 Spring 中只配置了一個這種類型的實例,否則報錯。(如果有多個那 Spring 就懵了,不知道該獲取哪一個)
    ② 按照 bean 的名字拿 bean:
    bean = (Bean) factory.getBean("beanName");
    註意:這種方法不太安全,IDE 不會檢查其安全性(關聯性)
    ③ 按照名字和類型拿 bean:(推薦)
    bean = (Bean) factory.getBean("beanName", Bean.class);
  • 【isSingleton】 用於判斷是否單例,如果判斷為真,其意思是該 Bean 在容器中是作為一個唯一單例存在的。而【isPrototype】則相反,如果判斷為真,意思是當你從容器中獲取 Bean,容器就為你生成一個新的實例。
    註意:在預設情況下,【isSingleton】為 ture,而【isPrototype】為 false
  • 關於 type 的匹配,這是一個按 Java 類型匹配的方式
  • 【getAliases】方法是獲取別名的方法

這就是 Spring IoC 最底層的設計,所有關於 Spring IoC 的容器將會遵守它所定義的方法。

ApplicationContext

根據 ApplicationContext 的類繼承關係圖,可以看到 ApplicationContext 介面擴展了許許多多的介面,因此它的功能十分強大,所以在實際應用中常常會使用到的是 ApplicationContext 介面,因為 BeanFactory 的方法和功能較少,而 ApplicationContext 的方法和功能較多。

通過上一篇 IoC 的例子,我們來認識一個 ApplicationContext 的子類——ClassPathXmlApplicationContext。

  1. 先在【src】目錄下創建一個 【bean.xml】 文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 通過 xml 方式裝配 bean -->
    <bean name="source" class="pojo.Source">
        <property name="fruit" value="橙子"/>
        <property name="sugar" value="多糖"/>
        <property name="size" value="超大杯"/>
    </bean>
</beans>
  1. 這裡定義了一個 bean ,這樣 Spring IoC 容器在初始化的時候就能找到它們,然後使用 ClassPathXmlApplicationContext 容器就可以將其初始化:
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Source source = (Source) context.getBean("source", Source.class);

System.out.println(source.getFruit());
System.out.println(source.getSugar());
System.out.println(source.getSize());

這樣就會使用 Application 的實現類 ClassPathXmlApplicationContext 去初始化 Spring IoC 容器,然後開發者就可以通過 IoC 容器來獲取資源了啦!

關於 Spring Bean 的裝配以及一些細節,會在下一篇文章中講到

ApplicationContext 常見實現類:

1.ClassPathXmlApplicationContext:
讀取classpath中的資源

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

2:FileSystemXmlApplicationContext:-
讀取指定路徑的資源

ApplicationContext ac = new FileSystemXmlApplicationContext("c:/applicationContext.xml");

3.XmlWebApplicationContext:
需要在Web的環境下才可以運行

XmlWebApplicationContext ac = new XmlWebApplicationContext(); // 這時並沒有初始化容器
ac.setServletContext(servletContext); // 需要指定ServletContext對象
ac.setConfigLocation("/WEB-INF/applicationContext.xml"); // 指定配置文件路徑,開頭的斜線表示Web應用的根目錄
ac.refresh(); // 初始化容器

BeanFactory 和 ApplicationContext 的區別:

  • BeanFactory:是Spring中最底層的介面,只提供了最簡單的IoC功能,負責配置,創建和管理bean。
    在應用中,一般不使用 BeanFactory,而推薦使用ApplicationContext(應用上下文),原因如下。
  • ApplicationContext:
    1.繼承了 BeanFactory,擁有了基本的 IoC 功能;
    2.除此之外,ApplicationContext 還提供了以下功能:
    ① 支持國際化;
    ② 支持消息機制;
    ③ 支持統一的資源載入;
    ④ 支持AOP功能;

Spring IoC 的容器的初始化和依賴註入

雖然 Spring IoC 容器的生成十分的複雜,但是大體瞭解一下 Spring IoC 初始化的過程還是必要的。這對於理解 Spring 的一系列行為是很有幫助的。

註意:Bean 的定義和初始化在 Spring IoC 容器是兩大步驟,它是先定義,然後初始化和依賴註入的。

  • Bean 的定義分為 3 步:
    1.Resource 定位
    Spring IoC 容器先根據開發者的配置,進行資源的定位,在 Spring 的開發中,通過 XML 或者註解都是十分常見的方式,定位的內容是由開發者提供的。
    2.BeanDefinition 的載入
    這個時候只是將 Resource 定位到的信息,保存到 Bean 定義(BeanDefinition)中,此時並不會創建 Bean 的實例
    3.BeanDefinition 的註冊
    這個過程就是將 BeanDefinition 的信息發佈到 Spring IoC 容器中
    註意:此時仍然沒有對應的 Bean 的實例。

做完了以上 3 步,Bean 就在 Spring IoC 容器中被定義了,而沒有被初始化,更沒有完成依賴註入,也就是沒有註入其配置的資源給 Bean,那麼它還不能完全使用。

對於初始化和依賴註入,Spring Bean 還有一個配置選項——【lazy-init】,其含義就是是否初始化 Spring Bean。在沒有任何配置的情況下,它的預設值為 default,實際值為 false,也就是 Spring IoC 預設會自動初始化 Bean。如果將其設置為 true,那麼只有當我們使用 Spring IoC 容器的 getBean 方法獲取它時,它才會進行 Bean 的初始化,完成依賴註入。


IoC 是如何實現的

最後我們簡單說說IoC是如何實現的。想象一下如果我們自己來實現這個依賴註入的功能,我們怎麼來做? 無外乎:

  1. 讀取標註或者配置文件,看看JuiceMaker依賴的是哪個Source,拿到類名
  2. 使用反射的API,基於類名實例化對應的對象實例
  3. 將對象實例,通過構造函數或者 setter,傳遞給 JuiceMaker

我們發現其實自己來實現也不是很難,Spring實際也就是這麼做的。這麼看的話其實IoC就是一個工廠模式的升級版!當然要做一個成熟的IoC框架,還是非常多細緻的工作要做,Spring不僅提供了一個已經成為業界標準的Java IoC框架,還提供了更多強大的功能,所以大家就別去造輪子啦!希望瞭解IoC更多實現細節不妨通過學習Spring的源碼來加深理解!

引用地址:這裡
【參考資料】:《Java EE 互聯網輕量級框架整合開發》、《Spring 實戰(第四版)》
【好文推薦】:①Spring 的本質系列(1) -- 依賴註入②Spring的IoC原理


歡迎轉載,轉載請註明出處!
@我沒有三顆心臟
CSDN博客:http://blog.csdn.net/qq939419061
簡書:http://www.jianshu.com/u/a40d61a49221


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

-Advertisement-
Play Games
更多相關文章
  • 在整體架構中引入消息中間件,勢必要考慮很多因素,比如成本及收益問題,怎麼樣才能達到最優的性價比?雖然消息中間件種類繁多,但是各自都有各自的側重點,選擇合適自己、揚長避短無疑是最好的方式。 ...
  • 狀態模式是根據其狀態變化來改變對象的行為,允許對象根據內部狀態來實現不同的行為。內容類可以具有大量的內部狀態,每當調用實現時,就委托給狀態類進行處理。 作用 當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變了其類。狀態模式主要解決的是當控制一個對象狀態的條件表達式過於複雜時的情況。把 ...
  • 面向對象設計的七大原則 今天我們要談的原則有七大原則,即:單一職責,里氏替換,迪米特法則,依賴倒轉,介面隔離,合成/聚合原則,開放-封閉 。 1. 開閉原則(Open-Closed Principle, OCP) 定義:軟體實體應當對擴展開放,對修改關閉。這句話說得有點專業,更通俗一點講,也就是:軟 ...
  • Python函數式編程 TOC + 函數參數中的魔法 + 位置參數 + 預設參數 + 動態參數 + 位置參數收集 + 關鍵字參數收集 + 收集參數行為的逆向過程(這個逆向過程用於實參上) + 參數傳遞 + 函數嵌套 + 命名空間 + 作用域 + 閉包 + 函數式編程 + 裝飾器 + 顯示方式 + @ ...
  • 變數的數據類型有數值型和引用型,基本數據類型變數1在java中添加時是存儲變數1的本身。而引用類型變數2在java添加時存儲的是變數2本身的地址,這個變數本身存在另一個地方。調用時是通過變數2的地址調用變數2的本身。具體點,數據存儲的東西叫“堆棧”,數據類型變數本身存在“堆棧”的棧中,而引用類型變數 ...
  • 練習 5.1: 修改findlinks代碼中遍歷n.FirstChild鏈表的部分,將迴圈調用visit,改成遞歸調用。 練習 5.2: 編寫函數,記錄在HTML樹中出現的同名元素的次數。 練習 5.3: 編寫函數輸出所有text結點的內容。註意不要訪問<script>和<style>元素,因為這些 ...
  • 測試測試測試 ...
  • 1本文的作用 一個從多個父類繼承過來的子類,可以訪問所有父類的功能。 2圖文介紹 3代碼驗證 參考:本文參考學習《Python3 Object Oriented Programming》,根據自己理解改編,Dusty Phillips 著 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...