Spring(2)——Spring IoC 詳解

Spring IoC 概述

IoC:Inverse of Control(控制反轉)

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

一個例子

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

在現實生活中,人們要用到同樣東西的時候,第一反應就是去找到這件東西,好比想喝新鮮橙汁,在沒有飲品店的日子裏,最直觀的作法就是:買果汁機、買橙子,而後準備開水。值得注意的是:這些都是你本身**「主動」創造**的過程,也就是說一杯橙汁須要你本身創造。git

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

請注意你並無「主動」去創造橙汁,橙汁是由飲品店創造的,而不是你,然而也徹底達到了你的要求,甚至比你創造的要好上那麼一些。web

Spring IoC 闡述

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

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

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


Spring IoC 容器

Spring 會提供 IoC 容器來管理和容納咱們所開發的各類各樣的 Bean,而且咱們能夠從中獲取各類發佈在 Spring IoC 容器裏的 Bean,而且經過描述能夠獲得它。微信

Spring IoC 容器的設計

Spring IoC 容器的設計主要是基於如下兩個接口:app

  • 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原理


歡迎轉載,轉載請註明出處! 簡書ID:@我沒有三顆心臟 github:wmyskxz 歡迎關注公衆微信號:wmyskxz_javaweb 分享本身的Java Web學習之路以及各類Java學習資料

相關文章
相關標籤/搜索