為了更好的理解用可以這樣通俗易懂的這樣講:IOC主要是說是new一個類來使用,方式分為:開發(fā)這手動創(chuàng)建和SpringIOC容器創(chuàng)建(控制反轉(zhuǎn))。
讀作“反轉(zhuǎn)控制”,更好理解,不是什么技術(shù),而是一種設(shè)計思想,就是將原本在程序中手動創(chuàng)建對象的控制權(quán),交由Spring框架來管理。
正控:若要使用某個對象,需要自己去負責(zé)對象的創(chuàng)建
反控:若要使用某個對象,只需要從 Spring 容器中獲取需要使用的對象,不關(guān)心對象的創(chuàng)建過程,也就是把創(chuàng)建對象的控制權(quán)反轉(zhuǎn)給了Spring框架
好萊塢法則:Don’t call me ,I’ll call you
控制反轉(zhuǎn)顯然是一個抽象的概念,我們舉一個鮮明的例子來說明。
在現(xiàn)實生活中,人們要用到一樣?xùn)|西的時候,第一反應(yīng)就是去找到這件東西,比如想喝新鮮橙汁,在沒有飲品店的日子里,最直觀的做法就是:買果汁機、買橙子,然后準備開水。值得注意的是:這些都是你自己“主動”創(chuàng)造的過程,也就是說一杯橙汁需要你自己創(chuàng)造。
然而到了今時今日,由于飲品店的盛行,當(dāng)我們想喝橙汁時,第一想法就轉(zhuǎn)換成了找到飲品店的聯(lián)系方式,通過電話等渠道描述你的需要、地址、聯(lián)系方式等,下訂單等待,過一會兒就會有人送來橙汁了。
請注意你并沒有“主動”去創(chuàng)造橙汁,橙汁是由飲品店創(chuàng)造的,而不是你,然而也完全達到了你的要求,甚至比你創(chuàng)造的要好上那么一些。
這就是一種控制反轉(zhuǎn)的理念,上述的例子已經(jīng)很好的說明了問題,我們再來描述一下控制反轉(zhuǎn)的概念:控制反轉(zhuǎn)是一種通過描述(在 Java 中可以是 XML 或者注解)并通過第三方(Spring)去產(chǎn)生或獲取特定對象的方式。
好處:
降低對象之間的耦合
我們不需要理解一個類的具體實現(xiàn),只需要知道它有什么用就好了(直接向 IoC 容器拿)
主動創(chuàng)建的模式中,責(zé)任歸于開發(fā)者,而在被動的模式下,責(zé)任歸于 IoC 容器,基于這樣的被動形式,我們就說對象被控制反轉(zhuǎn)了。(也可以說是反轉(zhuǎn)了控制)
Spring 會提供 IoC 容器來管理和容納我們所開發(fā)的各種各樣的 Bean,并且我們可以從中獲取各種發(fā)布在 Spring IoC 容器里的 Bean,并且通過描述可以得到它。
Spring IoC 容器的設(shè)計主要是基于以下兩個接口:
BeanFactory
ApplicationContext
其中 ApplicationContext 是 BeanFactory 的子接口之一,換句話說:BeanFactory 是 Spring IoC 容器所定義的最底層接口,而 ApplicationContext 是其最高級接口之一,并對 BeanFactory 功能做了許多的擴展,所以在絕大部分的工作場景下,都會使用 ApplicationContext 作為 Spring IoC 容器。
從上圖中我們可以幾乎看到, BeanFactory 位于設(shè)計的最底層,它提供了 Spring IoC 最底層的設(shè)計,為此,我們先來看看該類中提供了哪些方法:
由于這個接口的重要性,所以有必要在這里作一下簡短的說明:
【getBean】 對應(yīng)了多個方法來獲取配置給 Spring IoC 容器的 Bean。
① 按照類型拿 bean:bean = (Bean) factory.getBean(Bean.class);
注意:要求在 Spring 中只配置了一個這種類型的實例,否則報錯。(如果有多個那 Spring 就懵了,不知道該獲取哪一個)
② 按照 bean 的名字拿 bean:bean = (Bean) factory.getBean("beanName");
注意:這種方法不太安全,IDE 不會檢查其安全性(關(guān)聯(lián)性)
③ 按照名字和類型拿 bean:(推薦)bean = (Bean) factory.getBean("beanName", Bean.class);
【isSingleton】 用于判斷是否單例,如果判斷為真,其意思是該 Bean 在容器中是作為一個唯一單例存在的。而【isPrototype】則相反,如果判斷為真,意思是當(dāng)你從容器中獲取 Bean,容器就為你生成一個新的實例。
注意:在默認情況下,【isSingleton】為 ture,而【isPrototype】為 false
關(guān)于 type 的匹配,這是一個按 Java 類型匹配的方式
【getAliases】方法是獲取別名的方法
這就是 Spring IoC 最底層的設(shè)計,所有關(guān)于 Spring IoC 的容器將會遵守它所定義的方法。
根據(jù) ApplicationContext 的類繼承關(guān)系圖,可以看到 ApplicationContext 接口擴展了許許多多的接口,因此它的功能十分強大,所以在實際應(yīng)用中常常會使用到的是 ApplicationContext 接口,因為 BeanFactory 的方法和功能較少,而 ApplicationContext 的方法和功能較多。
通過上一篇 IoC 的例子,我們來認識一個 ApplicationContext 的子類——ClassPathXmlApplicationContext。
先在【src】目錄下創(chuàng)建一個 【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>
這里定義了一個 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 的實現(xiàn)類 ClassPathXmlApplicationContext 去初始化 Spring IoC 容器,然后開發(fā)者就可以通過 IoC 容器來獲取資源了啦!
關(guān)于 Spring Bean 的裝配以及一些細節(jié),會在下一篇文章中講到
1.ClassPathXmlApplicationContext:
讀取classpath中的資源
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
2:FileSystemXmlApplicationContext:-
讀取指定路徑的資源
ApplicationContext ac = new FileSystemXmlApplicationContext("c:/applicationContext.xml");
3.XmlWebApplicationContext:
需要在Web的環(huán)境下才可以運行
XmlWebApplicationContext ac = new XmlWebApplicationContext(); // 這時并沒有初始化容器ac.setServletContext(servletContext); // 需要指定ServletContext對象ac.setConfigLocation("/WEB-INF/applicationContext.xml"); // 指定配置文件路徑,開頭的斜線表示W(wǎng)eb應(yīng)用的根目錄ac.refresh(); // 初始化容器
BeanFactory:是Spring中最底層的接口,只提供了最簡單的IoC功能,負責(zé)配置,創(chuàng)建和管理bean。
在應(yīng)用中,一般不使用 BeanFactory,而推薦使用ApplicationContext(應(yīng)用上下文),原因如下。
ApplicationContext:
1.繼承了 BeanFactory,擁有了基本的 IoC 功能;
2.除此之外,ApplicationContext 還提供了以下功能:
① 支持國際化;
② 支持消息機制;
③ 支持統(tǒng)一的資源加載;
④ 支持AOP功能;
雖然 Spring IoC 容器的生成十分的復(fù)雜,但是大體了解一下 Spring IoC 初始化的過程還是必要的。這對于理解 Spring 的一系列行為是很有幫助的。
注意:Bean 的定義和初始化在 Spring IoC 容器是兩大步驟,它是先定義,然后初始化和依賴注入的。
Bean 的定義分為 3 步:
1.Resource 定位
Spring IoC 容器先根據(jù)開發(fā)者的配置,進行資源的定位,在 Spring 的開發(fā)中,通過 XML 或者注解都是十分常見的方式,定位的內(nèi)容是由開發(fā)者提供的。
2.BeanDefinition 的載入
這個時候只是將 Resource 定位到的信息,保存到 Bean 定義(BeanDefinition)中,此時并不會創(chuàng)建 Bean 的實例
3.BeanDefinition 的注冊
這個過程就是將 BeanDefinition 的信息發(fā)布到 Spring IoC 容器中
注意:此時仍然沒有對應(yīng)的 Bean 的實例。
做完了以上 3 步,Bean 就在 Spring IoC 容器中被定義了,而沒有被初始化,更沒有完成依賴注入,也就是沒有注入其配置的資源給 Bean,那么它還不能完全使用。
對于初始化和依賴注入,Spring Bean 還有一個配置選項——【lazy-init】,其含義就是是否初始化 Spring Bean。在沒有任何配置的情況下,它的默認值為 default,實際值為 false,也就是 Spring IoC 默認會自動初始化 Bean。如果將其設(shè)置為 true,那么只有當(dāng)我們使用 Spring IoC 容器的 getBean 方法獲取它時,它才會進行 Bean 的初始化,完成依賴注入。
來源:https://www.icode9.com/content-4-595351.html