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