Spring依賴注入(控制反轉(zhuǎn))DI(IOC)的常用方式(構(gòu)造器注入和setter注入)


平常的java開發(fā)中特碳,程序員在某個(gè)類中需要依賴其它類的方法诚亚,通常是new一個(gè)依賴類再調(diào)用類實(shí)例的方法,這種開發(fā)存在的問(wèn)題是new的類實(shí)例不好統(tǒng)一管理午乓,spring提出了依賴注入的思想站宗,即依賴類不由程序員實(shí)例化,而是通過(guò)spring容器幫我們new指定實(shí)例并且將實(shí)例注入到需要該對(duì)象的類中益愈。依賴注入的另一種說(shuō)法是“控制反轉(zhuǎn)”梢灭,通俗的理解是:平常我們new一個(gè)實(shí)例,這個(gè)實(shí)例的控制權(quán)是我們程序員蒸其,而控制反轉(zhuǎn)是指new實(shí)例工作不由我們程序員來(lái)做而是交給spring容器來(lái)做敏释。

通常使用setter方法和構(gòu)造器方式來(lái)進(jìn)行注入,在過(guò)去的開發(fā)過(guò)程中摸袁,這兩種注入方式都是非常常用的钥顽。spring也同時(shí)支持這兩種依賴注入的方式:設(shè)值注入和構(gòu)造注入。這兩種依賴注入的方式并沒有絕對(duì)的好壞靠汁,知識(shí)適應(yīng)的場(chǎng)景不一樣蜂大。

相比而言setter注入具有以下優(yōu)點(diǎn):

1)與傳統(tǒng)的JavaBean的寫法更相似湿蛔,程序開發(fā)人員更容易理解、接受县爬。通過(guò)setter方法設(shè)定依賴關(guān)系顯得更加直觀阳啥、自然。
2)對(duì)于復(fù)雜的依賴關(guān)系财喳,如果采用構(gòu)造注入察迟,會(huì)導(dǎo)致構(gòu)造器過(guò)于臃腫,難以閱讀耳高。Spring在創(chuàng)建Bean實(shí)例時(shí)扎瓶,需要同時(shí)實(shí)例化其依賴的全部實(shí)例,因而導(dǎo)致性能下降泌枪。而是用設(shè)置注入可以避免這些問(wèn)題概荷。
3)尤其在某些屬性可選的情況下,多參數(shù)的構(gòu)造器更加笨重碌燕。

某些情況下误证,構(gòu)造注入的優(yōu)勢(shì):


1)構(gòu)造注入可以再構(gòu)造器中決定依賴關(guān)系的注入順序,有限依賴的優(yōu)先注入修壕。例如愈捅,組件中其它依賴關(guān)系的注入,常常需要依賴于Datasource的注入慈鸠。采用構(gòu)造注入蓝谨,可以在代碼中清晰地決定注入順序。
2)對(duì)于依賴關(guān)系無(wú)需變化的Bean青团,構(gòu)造注入更加有用譬巫。因?yàn)闆]有setter方法,所有的依賴關(guān)系全部在構(gòu)造器內(nèi)設(shè)定督笆。因此芦昔,無(wú)需擔(dān)心后續(xù)代碼對(duì)依賴關(guān)系的破壞。
3)依賴關(guān)系只能在構(gòu)造器中設(shè)定胖腾,則只有組建的創(chuàng)建者才能改變組建的依賴關(guān)系烟零。隊(duì)組建的調(diào)用者而言,組件內(nèi)部的依賴關(guān)系完全透明咸作,更符合高內(nèi)聚的原則锨阿。

建議:采用設(shè)置注入為主,構(gòu)造注入為輔的注入策略记罚。對(duì)于依賴關(guān)系無(wú)需變化的注入墅诡,盡量采用構(gòu)造注入;而其它的依賴關(guān)系的注入,則考慮設(shè)值注入末早。


一烟馅、構(gòu)造器注入

這種方式的注入是指帶有參數(shù)的構(gòu)造函數(shù)注入,再定義屬性類時(shí),需要定義帶有參數(shù)的構(gòu)造器然磷,屬性值通過(guò)這一構(gòu)造器注入到對(duì)象中

相對(duì)于使用setter方式進(jìn)行注入郑趁,使用構(gòu)造器注入時(shí),明確了哪些屬性是必須的姿搜,通過(guò)構(gòu)造強(qiáng)制依賴關(guān)系寡润,不可能實(shí)例化不完全的或無(wú)法使用的bean。

構(gòu)造器注入主要有兩種方式:

  • 使用<constructor-arg>元素

  • 使用Spring3.0引入的c命名空間

使用<construtor-arg>元素進(jìn)行構(gòu)造器注入時(shí)會(huì)使得xml配置文件相對(duì)繁瑣舅柜,但有時(shí)能比使用c命名空間進(jìn)行注入具有更多功能

1梭纹、使用<constructor-arg>元素進(jìn)行注入

屬性類:

public class SpringAction {
    //注入對(duì)象springDao
    private String name;
    private int salary;
    private User user;
    
    //此處必須提供含參數(shù)的構(gòu)造函數(shù)用于注入相關(guān)屬性
    public SpringAction(String name,int salary,User user){
        this.name = name;
        this.salary = salary;
        this.user = user;
        System.out.println("構(gòu)造方法調(diào)用屬性");
    }
        
        public void save(){
        ...
    }
}

配置文件beans.xml

<!--配置bean,配置后該類由spring管理-->
<bean name="user" class="com.bless.springdemo.vo.User"></bean>

--很久參數(shù)索引賦值--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
     <constructor-arg index="0" value="劉曉剛" />
     <constructor-arg index="1" value="3500" />
     <constructor-arg index="2" ref="user"/>
</bean>

--根據(jù)參數(shù)類型賦值--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
     <constructor-arg type="Java.lang.String" value="劉曉剛" />
     <constructor-arg type="java.lang.Intager" value="3500" />
     <constructor-arg type="com.bless.springdemo.vo.User" ref="user"/>
</bean>

--根據(jù)參數(shù)名稱賦值--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
     <constructor-arg name="name" value="劉曉剛" />
     <constructor-arg name="salary" value="3500" />
     <constructor-arg name="user" ref="user"/>
</bean>

--按照參數(shù)順序直接賦值(value)--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
     <constructor-arg value="劉曉剛" />
     <constructor-arg value="3500" />
     <constructor-arg ref="user"/>
</bean>

2、使用c命名空間注入

spring3.0版本后添加的注入方式致份,簡(jiǎn)化了xml配置文件內(nèi)容

配置文件beans.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"
    xmlns:p="http://www.springframework.org/schema/c"       ////使用命名空間時(shí)变抽,注意頭文件這里要多出這一行
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<!--配置bean,配置后該類由spring管理-->
<bean name="user" class="com.bless.springdemo.vo.User"></bean>

<bean name="springAction" class="com.bless.springdemo.action.SpringAction" 
      c:name-value="小明" 
      c:salary-value="2300"
      c:user-ref="user"/>

--也可以這樣使用ref屬性--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction" 
      c:_-ref="user"/>    

--當(dāng)只使用value屬性時(shí)可以這樣--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction" 
      c:_value="小明" 
      c:_salary="2300"/>
      
<bean name="springAction" class="com.bless.springdemo.action.SpringAction" 
      c:_0="小明" 
      c:_1="2300"/>
      
</beans>

二、setter注入

1氮块、常量和bean注入(使用<property>標(biāo)簽)

屬性類:

public class SpringAction {
    //注入對(duì)象springDao
    private String name;
    private int salary;
    private User user;
    
    //此處一定要有屬性的setter方法
    public void setName(String name) { 
        this.name = name; 
    } 
    
    public void setSalary(Salary salary) { 
        this.salary = salary; 
    } 
    
    public void setUser(User user) { 
        this.user = user; 
    } 
        
        public void save(){
        ...
    }
}

配置文件beans.xml

<!--配置bean,配置后該類由spring管理-->
<bean name="user" class="com.bless.springdemo.vo.User"></bean>

--很久參數(shù)索引賦值--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
     <property index="0" value="jane"/>
     <property index="1" value="3500" />
     <property index="2" ref="user"/>
</bean>

--根據(jù)參數(shù)類型賦值--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
     <property type="Java.lang.String" value="劉曉剛" />
     <property type="java.lang.Intager" value="3500" />
     <property type="com.bless.springdemo.vo.User" ref="user"/>
</bean>

--根據(jù)參數(shù)名稱賦值--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
     <property name="name" value="劉曉剛" />
     <property name="salary" value="3500" />
     <property name="user" ref="user"/>
</bean>

--按照參數(shù)順序直接賦值(value)--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
     <property value="劉曉剛" />
     <property value="3500" />
     <property ref="user"/>
</bean>

2绍载、集合對(duì)象注入

配置文件beans.xml

<!--配置bean,配置后該類由spring管理-->
<bean name="user" class="com.bless.springdemo.vo.User"></bean>

--注入list參數(shù)--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
     <property index="0">
        <list>
            <value>小紅</value>
            <value>小明</value>
            <value>小剛</value>
        </list>
     </property>
</bean>

--在list中引用bean--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
     <property index="0">
        <list>
            <ref bean="user"/>
            <ref bean="student"/>
        </list>
     </property>
</bean>

--注入map參數(shù)--
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
     <property name="map">
        <map>
            <entry key="name" value="小明"/>
            <entry key="name" value="小紅"/>
            <entry key="name" value="小剛"/>
        </map>
     </property>
</bean>

--null注入--
<property name="wife"><null/></property>

3、p命名空間注入

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"       ////使用命名空間時(shí)雇锡,注意頭文件這里要多出這一行
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<!--配置bean,配置后該類由spring管理-->
<bean name="user" class="com.bless.springdemo.vo.User"></bean>

<bean name="springAction" class="com.bless.springdemo.action.SpringAction" 
      p:name="小明" 
      c:salary="2300"
      c:user-ref="user"/>
      
</beans>

4逛钻、使用util命名空間進(jìn)行集合注入(了解僚焦,p命名空間不能注入集合)

三锰提、工廠方法注入

1、靜態(tài)工廠的方法注入

靜態(tài)工廠顧名思義芳悲,就是通過(guò)調(diào)用靜態(tài)工廠的方法來(lái)獲取自己需要的對(duì)象立肘,為了讓spring管理所有對(duì)象,我們不能直接通過(guò)"工程類.靜態(tài)方法()"來(lái)獲取對(duì)象名扛,而是依然通過(guò)spring注入的形式獲攘履辍:

package com.bless.springdemo.factory; 

import com.bless.springdemo.dao.FactoryDao; 
import com.bless.springdemo.dao.impl.FactoryDaoImpl; 
import com.bless.springdemo.dao.impl.StaticFacotryDaoImpl; 

public class DaoFactory { 
    //靜態(tài)工廠 
    public static final FactoryDao getStaticFactoryDaoImpl(){ 
        return new StaticFacotryDaoImpl(); 
    } 
}

同樣看關(guān)鍵類,這里我需要注入一個(gè)FactoryDao對(duì)象肮韧,這里看起來(lái)跟第一種注入一模一樣融蹂,但是看隨后的xml會(huì)發(fā)現(xiàn)有很大差別

public class SpringAction { 
    //注入對(duì)象 
    private FactoryDao staticFactoryDao; 

    public void staticFactoryOk(){ 
        staticFactoryDao.saveFactory(); 
    } 
    //注入對(duì)象的set方法 
    public void setStaticFactoryDao(FactoryDao staticFactoryDao) { 
        this.staticFactoryDao = staticFactoryDao; 
    } 
} 

Spring的IOC配置文件,注意看<bean name="staticFactoryDao">指向的class并不是FactoryDao的實(shí)現(xiàn)類弄企,而是指向靜態(tài)工廠DaoFactory超燃,并且配置 factory-method="getStaticFactoryDaoImpl"指定調(diào)用哪個(gè)工廠方法:

<!--配置bean,配置后該類由spring管理--> 
<bean name="springAction" class="com.bless.springdemo.action.SpringAction" > 
    <!--(3)使用靜態(tài)工廠的方法注入對(duì)象,對(duì)應(yīng)下面的配置文件(3)--> 
    <property name="staticFactoryDao" ref="staticFactoryDao"></property> 
    </property> 
</bean> 
<!--(3)此處獲取對(duì)象的方式是從工廠類中獲取靜態(tài)方法--> 
<bean name="staticFactoryDao" class="com.bless.springdemo.factory.DaoFactory" factory-method="getStaticFactoryDaoImpl"></bean> 

4.實(shí)例工廠的方法注入

實(shí)例工廠的意思是獲取對(duì)象實(shí)例的方法不是靜態(tài)的,所以你需要首先new工廠類拘领,再調(diào)用普通的實(shí)例方法:

public class DaoFactory { 
    //實(shí)例工廠 
    public FactoryDao getFactoryDaoImpl(){ 
        return new FactoryDaoImpl(); 
    } 
}

那么下面這個(gè)類沒什么說(shuō)的意乓,跟前面也很相似,但是我們需要通過(guò)實(shí)例工廠類創(chuàng)建FactoryDao對(duì)象:

public class SpringAction { 
    //注入對(duì)象 
    private FactoryDao factoryDao; 
    
    public void factoryOk(){ 
        factoryDao.saveFactory(); 
    } 
    
    public void setFactoryDao(FactoryDao factoryDao) { 
        this.factoryDao = factoryDao; 
    } 
} 

最后看spring配置文件:

<!--配置bean,配置后該類由spring管理--> 
<bean name="springAction" class="com.bless.springdemo.action.SpringAction"> 
    <!--(4)使用實(shí)例工廠的方法注入對(duì)象,對(duì)應(yīng)下面的配置文件(4)--> 
    <property name="factoryDao" ref="factoryDao"></property> 
</bean> 

<!--(4)此處獲取對(duì)象的方式是從工廠類中獲取實(shí)例方法--> 
<bean name="daoFactory" class="com.bless.springdemo.factory.DaoFactory"></bean> 
<bean name="factoryDao" factory-bean="daoFactory" factory-method="getFactoryDaoImpl"></bean> 

四约素、另外注意:

通過(guò)Spring創(chuàng)建的對(duì)象默認(rèn)是單例的届良,如果需要?jiǎng)?chuàng)建多實(shí)例對(duì)象可以在<bean>標(biāo)簽后面添加一個(gè)屬性:

<bean name="..." class="..." scope="prototype">  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末笆凌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子士葫,更是在濱河造成了極大的恐慌乞而,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慢显,死亡現(xiàn)場(chǎng)離奇詭異晦闰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)鳍怨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門呻右,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人鞋喇,你說(shuō)我怎么就攤上這事声滥。” “怎么了侦香?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵落塑,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我罐韩,道長(zhǎng)憾赁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任散吵,我火速辦了婚禮龙考,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘矾睦。我一直安慰自己晦款,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布枚冗。 她就那樣靜靜地躺著缓溅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赁温。 梳的紋絲不亂的頭發(fā)上坛怪,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音股囊,去河邊找鬼袜匿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛毁涉,可吹牛的內(nèi)容都是我干的沉帮。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼穆壕!你這毒婦竟也來(lái)了待牵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤喇勋,失蹤者是張志新(化名)和其女友劉穎缨该,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體川背,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贰拿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年砸抛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浸颓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片些举。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡湾碎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出米同,到底是詐尸還是另有隱情端铛,我是刑警寧澤蚤告,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布练般,位于F島的核電站矗漾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏薄料。R本人自食惡果不足惜敞贡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望摄职。 院中可真熱鬧誊役,春花似錦、人聲如沸琳钉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)歌懒。三九已至,卻和暖如春溯壶,著一層夾襖步出監(jiān)牢的瞬間及皂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工且改, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留验烧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓又跛,卻偏偏與公主長(zhǎng)得像碍拆,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

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