Spring的IoC容器

Spring是一個(gè)輕量級(jí)的Java開(kāi)發(fā)框架耿导,其提供的兩大基礎(chǔ)功能為IoC和AOP,其中IoC為依賴(lài)反轉(zhuǎn)(Inversion of Control)。IOC容器的基本理念就是“為別人服務(wù)”,那為別人服務(wù)什么呢巩螃?其中最重要就是業(yè)務(wù)對(duì)象的構(gòu)建管理和業(yè)務(wù)對(duì)象之間的依賴(lài)綁定

  • 業(yè)務(wù)對(duì)象的構(gòu)建管理:業(yè)務(wù)場(chǎng)景中匕争,無(wú)需關(guān)心業(yè)務(wù)對(duì)象如何創(chuàng)建、如何管理爷耀,在需要時(shí)只需獲取即可甘桑。業(yè)務(wù)對(duì)象的構(gòu)建管理交給IoC容器,避免這部分代碼對(duì)業(yè)務(wù)邏輯的侵染歹叮。
  • 業(yè)務(wù)對(duì)象之間的依賴(lài)綁定:IoC容器需要先了解業(yè)務(wù)對(duì)象之間的依賴(lài)關(guān)系跑杭,這樣依據(jù)之前業(yè)務(wù)對(duì)象的構(gòu)建管理就可以對(duì)外提供IoC服務(wù),保證每個(gè)業(yè)務(wù)對(duì)象在使用時(shí)處于就緒狀態(tài)咆耿。

IoC容器管理業(yè)務(wù)對(duì)象德谅,首先需要知道業(yè)務(wù)對(duì)象之間的依賴(lài)關(guān)系,以下有幾種方式告訴IoC容器其管理的對(duì)象之間的綁定關(guān)系:

  • 可以通過(guò)簡(jiǎn)單的文本方式記錄被注入對(duì)象和其依賴(lài)對(duì)象的對(duì)應(yīng)關(guān)系萨螺。
  • 使用描述性更強(qiáng)的XML文件格式記錄對(duì)象之間的對(duì)應(yīng)關(guān)系窄做。
  • 還可以通過(guò)編寫(xiě)代碼的方式(調(diào)用IoC容器提供的對(duì)應(yīng)API)設(shè)置對(duì)象之間的關(guān)系。
  • ...

注意:不管是什么方式來(lái)告知IoC容器對(duì)象之間的綁定關(guān)系慰技,最終都是通過(guò)編碼方式(調(diào)用IOC提供的API)來(lái)將這些信息"寫(xiě)入"到IoC容器中的椭盏。

2種基本的容器類(lèi)型

Spring的IoC容器提供兩種基本的容器類(lèi)型:BeanFactory和ApplicationContext。

  • BeanFactory:基礎(chǔ)類(lèi)型IoC容器吻商,提供基本的容器服務(wù)掏颊,如果沒(méi)有特殊指定,采用延遲初始化策略艾帐,也就是當(dāng)客戶(hù)端需要容器中某個(gè)對(duì)象時(shí)乌叶,才對(duì)該受管理的對(duì)象初始化及其依賴(lài)注入操作。所以柒爸,相對(duì)來(lái)說(shuō)准浴,BeanFactory容器啟動(dòng)較快,所需資源有限揍鸟,對(duì)于資源有限兄裂,并且功能要求不嚴(yán)格的場(chǎng)景句旱,使用BeanFactory容器是比較合適的。
  • ApplicationContext:ApplicationContext是在BeanFactory基礎(chǔ)之上構(gòu)建的晰奖,是一個(gè)比較高級(jí)的容器谈撒,除了擁有BeanFactory的全部功能外,也提供其他高級(jí)特性匾南,比如事件發(fā)布啃匿、國(guó)際化信息支持等。ApplicationContext所管理的對(duì)象蛆楞,默認(rèn)ApplicationContext啟動(dòng)之后全部初始化并綁定完成溯乒,所以其啟動(dòng)較慢,占用資源較多豹爹。在系統(tǒng)資源充足裆悄,并需要提供較多功能的使用場(chǎng)景,ApplicationContext是一個(gè)不錯(cuò)的選擇臂聋。

依賴(lài)注入的3種方式

  • 構(gòu)造方法注入:調(diào)用被注入對(duì)象的構(gòu)造方然注入光稼,優(yōu)點(diǎn)是對(duì)象在構(gòu)造完成就進(jìn)入了就緒狀態(tài)。
  • 屬性注入:調(diào)用被注入對(duì)象的setter/getter方法孩等。
  • 接口注入:現(xiàn)在不提倡的一種方式艾君,因?yàn)樗鼜?qiáng)制被注入對(duì)象實(shí)現(xiàn)不必要的接口,帶有侵入性肄方。

spring的bean配置(XML配置方式)

屬性注入即通過(guò) setter 方法注入Bean 的屬性值或依賴(lài)的對(duì)象冰垄,使用 <property> 元素, 使用 name 屬性指定 Bean 的屬性名稱(chēng),value 屬性或 <value> 子節(jié)點(diǎn)指定屬性值权她,屬性注入是實(shí)際應(yīng)用中最常用的注入方式虹茶。屬性注入Bean類(lèi)須有一個(gè)默認(rèn)的構(gòu)造方法。

<!-- Hello類(lèi)中有一個(gè)String類(lèi)型的msg屬性 -->
<bean id="hello" class="com.luoxn28.Hello">
    <property name="msg" value="luoxn28"/>
</bean>

通過(guò)構(gòu)造方法注入Bean 的屬性值或依賴(lài)的對(duì)象隅要,它保證了 Bean 實(shí)例在實(shí)例化后就可以使用写烤,構(gòu)造器注入在 <constructor-arg> 元素里聲明屬性。

<bean id="msg" class="java.lang.String">
    <constructor-arg value="string"/>
</bean>

<!-- 按照索引匹配入?yún)?-->
<bean id="car" class="com.luoxn28.Car">
    <constructor-arg value="比亞迪" index="0"/>
    <constructor-arg value="中國(guó)制造" index="1"/>
    <constructor-arg value="200000" index="2"/>
</bean>
<!-- 按照類(lèi)型匹配入?yún)?-->
<bean id="car2" class="com.luoxn28.Car">
    <constructor-arg value="比亞迪" type="java.lang.String">
    <constructor-arg value="中國(guó)制造" type="java.lang.String"/>
    <constructor-arg value="200000" type="double"/>
</bean>

多個(gè)Bean依賴(lài)配置拾徙,需在Bean配置中指定對(duì)Bean的引用洲炊。既可以使用"ref"屬性配置,也可以直接在屬性里包含Bean的配置尼啡,即內(nèi)部Bean暂衡。內(nèi)部Bean只能在當(dāng)前定義處使用,貌似其他地方也沒(méi)法使用哈 :)

<bean id="msg" class="java.lang.String">
    <constructor-arg value="luoxn28"/>
</bean>

<!-- Hello類(lèi)中有一個(gè)String類(lèi)型的msg屬性 -->
<bean id="hello" class="com.luoxn28.Hello">
    <property name="msg" ref="msg"/>
</bean>

<!-- Hello類(lèi)中有一個(gè)String類(lèi)型的msg屬性 -->
<bean id="hello" class="com.luoxn28.Hello">
    <property name="msg">
        <bean class="java.lang.String">
            <constructor-arg value="luoxn28"/>
        </bean>
    </property>
</bean>

如果Bean屬性是集合/容器類(lèi)型崖瞭,則通過(guò)<list>/<set>/<map>來(lái)配置狂巢。

<!-- CollectionClass類(lèi)有3個(gè)屬性,List<String> list书聚、Set<String> set唧领、Map<String, String> map-->
<bean id="collectionClass" class="com.luoxn28.CollectionClass">
    <property name="list">
        <list>
            <value>luoxn28</value>
            <value>luoxn29</value>
            <value>luoxn30</value>
        </list>
    </property>
    <property name="set">
        <set>
            <value>luoxn28</value>
            <value>luoxn29</value>
            <value>luoxn30</value>
        </set>
    </property>
    <property name="map">
        <map>
            <entry key="str1" value="luoxn28"/>
            <entry key="str2"><value>luoxn29</value></entry>
            <entry key="str3"><value>luoxn30</value></entry>
        </map>
    </property>
</bean>

Bean的作用域

Spring最初提供ean的兩種scope類(lèi)型:singleton和prototype藻雌,在發(fā)布2.0之后,新增了request斩个、session和global session類(lèi)型胯杭,不過(guò)這3種新增的只能用在Web應(yīng)用中∈苌叮可以通過(guò)bean屬性scope來(lái)指定bean的scope類(lèi)型做个,如果是singleton類(lèi)型的話(huà),在用戶(hù)獲取該bean之后滚局,容器還是會(huì)接管該bean的生命周期居暖;如果是prototype的話(huà),在用戶(hù)獲取該bean之后藤肢,容器就不接管該bean了太闺,也就是容器每次會(huì)創(chuàng)建一個(gè)新的bean對(duì)象返回給用戶(hù)。

<!-- Hello對(duì)象每次獲取都會(huì)新建 -->
<bean id="hello" class="com.luoxn28.Hello" scope="prototype">
    <property name="msg" value="luoxn28"/>
</bean>

通過(guò)靜態(tài)方法創(chuàng)建bean

調(diào)用靜態(tài)工廠(chǎng)方法創(chuàng)建 Bean是將對(duì)象創(chuàng)建的過(guò)程封裝到靜態(tài)方法中嘁圈,當(dāng)用戶(hù)需要對(duì)象時(shí)跟束,只需要簡(jiǎn)單地調(diào)用靜態(tài)方法特铝,而不同關(guān)心創(chuàng)建對(duì)象的細(xì)節(jié)。要聲明通過(guò)靜態(tài)方法創(chuàng)建的 Bean, 需要在 Bean 的 class 屬性里指定擁有該工廠(chǎng)的方法的類(lèi), 同時(shí)在 factory-method 屬性里指定工廠(chǎng)方法的名稱(chēng). 最后, 使用 <constrctor-arg> 元素為該方法傳遞方法參數(shù)台谢。

public static Hello createHello() {
    return new Hello();
}

<bean id="hello" class="com.luoxn28.Hello" factory-method="createHello">
</bean>

BeanFactory

Spring 中有兩種類(lèi)型的 Bean愧捕, 一種是普通Bean,另一種是工廠(chǎng)Bean乳愉,即FactoryBean。工廠(chǎng) Bean 跟普通Bean不同,,其返回的對(duì)象不是指定類(lèi)的一個(gè)實(shí)例仗岖,其返回的是該工廠(chǎng) Bean 的 getObject 方法所返回的對(duì)象
FactoryBean接口源碼如下所示:

public interface FactoryBean<T> {
    // 返回的實(shí)例
    T getObject() throws Exception;
    // 返回的類(lèi)型
    Class<?> getObjectType();
    // 是否為單例
    boolean isSingleton();
}

BeanFactory使用示例:

public class Hello {
    private String name;
    private int age;
    // set/get方法
}

public class HelloBeanFactory implements FactoryBean<Hello> {
    @Override
    public Hello getObject() throws Exception {
        Hello hello = new Hello();

        hello.setName("luoxn28");
        hello.setAge(23);
        return hello;
    }

    @Override
    public Class<?> getObjectType() {
        return Hello.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

然后在applicationContext.xml中配置如下,就可以獲取Hello類(lèi)實(shí)例了览妖。

<bean id="helloBean" class="com.luoxn28.hello.HelloBeanFactory">
</bean>

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

    Hello hello = context.getBean("helloBean", Hello.class);
    System.out.println(hello);
}

參考資料:

  1. Spring的IoC容器
  2. 《Spring揭秘》IOC章節(jié)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末轧拄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子讽膏,更是在濱河造成了極大的恐慌檩电,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件府树,死亡現(xiàn)場(chǎng)離奇詭異俐末,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)奄侠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén)卓箫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人垄潮,你說(shuō)我怎么就攤上這事烹卒∶瓶” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵旅急,是天一觀的道長(zhǎng)逢勾。 經(jīng)常有香客問(wèn)我,道長(zhǎng)坠非,這世上最難降的妖魔是什么敏沉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮炎码,結(jié)果婚禮上盟迟,老公的妹妹穿的比我還像新娘。我一直安慰自己潦闲,他們只是感情好攒菠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著歉闰,像睡著了一般辖众。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上和敬,一...
    開(kāi)封第一講書(shū)人閱讀 51,763評(píng)論 1 307
  • 那天凹炸,我揣著相機(jī)與錄音,去河邊找鬼昼弟。 笑死啤它,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的舱痘。 我是一名探鬼主播变骡,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼芭逝!你這毒婦竟也來(lái)了塌碌?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤旬盯,失蹤者是張志新(化名)和其女友劉穎台妆,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體胖翰,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡频丘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了泡态。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搂漠。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖某弦,靈堂內(nèi)的尸體忽然破棺而出桐汤,到底是詐尸還是另有隱情而克,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布怔毛,位于F島的核電站员萍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拣度。R本人自食惡果不足惜碎绎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抗果。 院中可真熱鬧筋帖,春花似錦、人聲如沸冤馏。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逮光。三九已至代箭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涕刚,已是汗流浹背嗡综。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杜漠,地道東北人极景。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像碑幅,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子塞绿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容