天天看點

Spring IOC容器(控制反轉和依賴注入)

Java知識點總結:想看的可以從這裡進入

目錄

    • 5、IoC容器
      • 5.1、介紹
      • 5.2、原理和實作
        • 5.2.1、BeanFactory
        • 5.2.2、ApplicationContext
      • 5.3、Bean的管理
        • 5.3.1、XML檔案管理
        • 5.3.2、注解管理
        • 5.3.3、bean的作用域

5、IoC容器

5.1、介紹

IOC是Inversion of Control的縮寫,我們稱為“控制反轉”。它于1996年,Michael Mattson在一篇有關探讨面向對象架構的文章中,首先提出了IOC 這個概念。IOC理論提出的觀點大體是:借助于“第三方”實作具有依賴關系的對象之間的解耦。

至于為什麼要解耦合,其實想想我們平時帶的機械手表就知道了,機械手表是由很多精密的齒輪等耦合在一起實作的,即便是其中一個很小的齒輪出現了錯誤,就會導緻整個手表運轉失誤。是以我們理想的系統才需要解耦合,就是為了不至于因為其中某個小失誤,導緻整個系統崩潰,而且解耦的系統也友善我們排查錯誤進行修改。

Spring IOC容器(控制反轉和依賴注入)

我們的Spring就是第三方,它通過IOC容器,使用各個Object完成互相之間解耦,這樣的話,當你在實作o1的時候,根本無須再去考慮2、3、4了,它使對象之間的耦合程度盡可能達到了一種較低的水準。(在此之前我們要使用o1,需要同時把o2,o3,o4都建立一遍)

控制反轉具體是什麼?舉個簡單的例子:我們想喝一杯果汁方法有兩個

  1. 自己準備材料、準備榨汁機,自己動手擷取一杯飲料(制造果汁的控制權完全在自己手中,想喝隻能自己買材料、自己動手制作)。
  2. 去飲品店購買,可以通過外賣、自己去買等多種方式(制造果汁的控制權在飲品店手中,我們隻負責去買,至于怎麼制作那就是飲品店自己的事了)。

以往的面向對象程式設計中,我們想在一個類中調用另一個類的對象和方法,需要使用 new 主動建立對象,以實作屬性方法的調用,此時對象的控制權是在調用的類中。但是控制反轉就是将控制權交由第三方(IoC容器),通過該IoC容器根據描述資訊去找尋使用者需要的資源,然後控制Java對象的執行個體化和初始化,管理對象和對象之間的依賴關系,這種控制權的轉變就是控制反轉的含義。其中IOC容器管理的java對象稱為SpringBean。

2004年,Martin Fowler探讨了一個問題:既然IOC是控制反轉,那麼到底是哪些方面的控制被反轉了呢?

經過詳細地分析和論證後,他得出了答案:獲得依賴對象的過程被反轉了,它由自身管理變為了由IOC容器主動注入。于是,他給“控制反轉”取了一個更合适的名字叫做“依賴注入(Dependency Injection)”。所謂依賴注入,就是由IOC容器在運作期間,動态地将某種依賴關系注入到對象之中。

是以,依賴注入(DI)和控制反轉(IOC)是從不同的角度的描述的同一件事情,就是指通過引入IOC容器,利用依賴關系注入的方式,實作對象之間的解耦。

Spring本質是一個生産管理Bean的第三方工廠,它按我們的需要生産管理Bean(第三方IOC容器通過我們的描述(XML、注解等),擷取生産特定的對象Bean,并進行管理),是以控制反轉是一種程式設計的思想,其中依賴注入是其解決Bean之間依賴的一種技術。學習這裡時可以了解一下工廠模式

IoC大大降低了對象之間的耦合,開發中甚至我們可以不用去了解,僅僅知道怎麼使用就可以(不過還是建議沒事看看人家的源碼,分析學習學習)。

5.2、原理和實作

在 Java 軟體開發過程中,系統中的各個對象之間、各個子產品之間、軟體系統和硬體系統之間,或多或少都存在一定的耦合關系,IOC就是通過工廠模式、Java 的反射機制、XML 解析等技術,将代碼的耦合度降低到最低限度。

實際上Spring是通過 BeanDefinition 這樣一個對象來描述它所管理的所有的Bean以及對象間的依賴關系,它将讀取的Bean的各種資訊統一都封裝成一個個的 BeanDefinition 對象,這樣就弱化了對Bean的定義,無論是通過什麼方式擷取的Bean對象,最終都是封裝成 BeanDefinition 注冊到IOC容器中,這樣呢,IOC就不必關注我們各種各樣的類和對象了,隻需要統一操作BeanDefinition 即可,在降低耦合程度上,還增加了擴充性和靈活性。依賴反轉功能都是圍繞這個BeanDefinition的處理來完成的。

IOC容器的底層最核心的就是兩個 Bean 工廠 接口:BeanFactory、ApplicationContext。IOC就是基于這兩個接口來設計的

5.2.1、BeanFactory

是Spring中最頂層的的 factory接口(org.springframework.beans.factory.BeanFactory),采用了Java經典的工廠名模式,也是最簡單的IOC容器,它定義了IOC的基本規範,在 BeanFactory 的基礎上 Spring 通過繼承逐層擴充容器的能力來實作一個完整的IOC。

BeanFacotry是Spring 内部的使用接口,不提供開發人員進行使用。采用了懶加載,容器在啟動後加載配置檔案時并不會馬上建立對象,而是而程式中擷取使用的時候才進行建立所需對象。

Spring IOC容器(控制反轉和依賴注入)

基于BeanFactory設計的層次結構,BeanFactory定義了基本的IoC容器的規範(如getBean可以擷取Bean對象等),其下三個子接口:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。

其中HierarchicalBeanFactory接口增加了getParentBeanFactory(),使BeanFactory具備了雙親IoC容器的管理功能。ConfigurableBeanFactory定義了一些對BeanFactory的配置功能(比如通過setParentBeanFactory()設定雙親IoC容器,通過addBeanPostProcessor()配置Bean後置處理器等等)。

ListableBeanFactory 接口表示這些 Bean 是可列的,AutowireCapableBeanFactory 接口定義 Bean 的自動裝配規則。

DefaultListableBeanFactory是BeanFactory層次中的最終實作,是一個簡單IoC容器的實作。像其他IoC容器比如XmlBeanFactory等等,都是在DefaultListableBeanFactory的基礎上做擴充。

它内部定義了一些基礎方法
1、Object getBean(String name):通過Bean的對象名擷取其執行個體
2、boolean containsBean(String name):檢視bean是否存在
3、boolean isSingleton(String name):是否是單例模式
4、boolean isPrototype(String name):是否是原型模式
5、boolean isTypeMatch(String name, ResolvableType typeToMatch):檢視一個bean對象是typeToMatch類型的
6、String[] getAliases(String name):傳回bean 的别名(bean标簽内name屬性設定的名稱)
7、Class<?> getType(String name):傳回 FactoryBean 建立的對象類型
           
Spring IOC容器(控制反轉和依賴注入)
BeanFactory和FactoryBean:
  • BeanFactory是IOC容器
  • FactoryBean是一個工廠Bean,可以生成某一個類型 Bean 的執行個體,可以讓我們自定義 Bean 的建立過程。它是IOC中一個具有特色的工廠Bean。

5.2.2、ApplicationContext

因為原始的BeanFactory的功能很簡單,很多技術和插件無法支援,是以衍生出了ApplicationContext 接口,它是BeanFactory的子接口,包含了BeanFactory的所有功能,并在其基礎上進行了擴充,增加了許多面向架構的特性,同時對應用環境做了許多适配。

  1. 支援資訊源,可以實作國際化。(MessageSource接口)
  2. 通路資源。(ResourcePatternResolver接口)
  3. 支援應用事件。(ApplicationEventPublisher)
  4. 在ApplicationContext中提供的附加服務

它采用的政策是立即加載,即在spring容器啟動,加載配置檔案後,就立即建立對象。因為使用Spring架構一般都會整合其他架構,是以把這些耗時耗記憶體的都在項目啟動的時候進行處理更加合适,是以一般開發人員使用 ApplicationContext接口。

Spring IOC容器(控制反轉和依賴注入)

ApplicationContext有幾個常用的實作類:(根據不同的配置方式使用不同的類來執行個體化)

  • 子類ClassPathXmlApplicationContext(“xml檔案”):從類路徑ClassPath中加載指定的 XML 配置檔案
  • 子類FileSystemXmlApplicationContext(“xml檔案”):加載磁盤路徑下的XML配置檔案
  • 子類AnnotationConfigApplicationContext(類.class):用于讀取(@Configuration)修飾的啟動類
  • 子類XmlWebApplicationContext:從web中擷取XML配置,預設情況下,配置将從“/WEB-INF/applicationContext.xml”擷取根上下文,從“/WEB-INF/test-servlet.xml”擷取具有命名空間“test-servlet”的上下

5.3、Bean的管理

IOC通常通過三種方式來管理Bean對象

  1. 基于xml配置檔案的方式實作
  2. 在Java接口和類中實作配置(通過注解 @Beam)
  3. 隐式的Bean的發現機制和自動裝配

這幾種方式應該遵循約定優于配置的原則,優先選擇通過 隐式的Bean的發現機制和自動裝配,其次選擇在Java接口和類中實作配置,最後選擇XML中配置。實際使用時是以三者混合使用,但優先級不同

5.3.1、XML檔案管理

XML檔案裝配對象

5.3.2、注解管理

使用注解裝配Bean

5.3.3、bean的作用域

預設情況下,所有的 Bean 都是單例的,也就是說在整個 Spring 應用中, Bean 的執行個體隻有一個。我們可以在 bean 标簽中添加 scope 屬性來配置 Bean 的作用範圍。

Spring 5 共提供了 6 種 scope 作用域:

  • singleton:預設值,單例模式
    • 執行個體化個數:1
    • 執行個體化機制:建立容器時建立(預設使用ApplicationContext),存儲在高速緩存中
    • 生命周期:
      • 建立:應用加載,建立容器,讀取配置檔案,對象直接建立
      • 運作:隻要容器在,對象就一直存在
      • 銷毀:當應用解除安裝時,銷毀容器,對象随之銷毀
  • prototype:原型模式
    • 執行個體化個數:多個
    • 執行個體化機制:隻有每次注入或者擷取Bean時,才會建立對象
    • 生命周期:
      • 建立:當使用對象時,對象建立
      • 運作:隻要對象在使用,就一直存活
      • 銷毀:對象一定時間内不使用,被java的垃圾回收期回收。
  • request
    • 執行個體化機制:每次請求都會建立一次
    • 生命周期
      • 建立:每次Http請求,使用對象時,對象建立
      • 運作:和Http請求中的request對象相同
      • 銷毀:處理完請求後銷毀
  • session:隻能在web開發中使用
    • 執行個體化機制:在一次會話期内建立一次
    • 生命周期
      • 建立:每一個會話期,使用對象時,對象建立
      • 運作:和一次session相同
      • 銷毀:随session銷毀而銷毀