Spring-IoC中裝配Bean

在Spring-IoC簡介中簡單介紹了什么是IoC以及一些相關(guān)的概念,這里將詳細(xì)介紹如何通過IoC容器提供的方法進(jìn)行注入和如何進(jìn)行注入配置。

依賴注入

IoC提供的依賴注入方法主要有屬性注入多糠、構(gòu)造函數(shù)注入和工廠方法注入,這里依次介紹如何通過各個方法注入Bean

屬性注入

屬性注入要求Bean提供一個默認(rèn)的構(gòu)造器,并為需要注入的屬性提供對應(yīng)的setter方法巡李。Spring會檢查Bean中是否有setter方法,但不會檢查是否有對應(yīng)的屬性成員扶认。
Bean的代碼如下侨拦。

public class Car{
    private int maxSpeed;
    private String brand;
    //如果要通過屬性注入則必須實(shí)現(xiàn)setter方法
    public void setXX(<T> XX){
        this.XX=XX;
    }
}

我們這里通過XML文件對Bean進(jìn)行設(shè)置,后面會詳細(xì)介紹所有的配置方式和配置內(nèi)容辐宾。

<bean id="car" class="Car">
    <property name="maxSpeed"><value>200</value></property>
    <property name="brand"><value>紅旗CA72</value></property>
</bean>

這樣設(shè)置完成后狱从,當(dāng)Spring啟動后,就會自動生成idcar叠纹,classCar季研,屬性分別為200紅旗CA72Bean
對于屬性的命名吊洼,要求變量的前兩個字母要么全部大寫训貌,要么全部小寫iCCard冒窍、iDCode是非法的。如果取非法的變量名豺鼻,在試圖啟動Spring時综液,將會失敗。因此命名的建議是像QQ儒飒、MSN谬莹、ID等正常以大寫字母出現(xiàn)的專業(yè)術(shù)語,在Java中一律使用小寫形式桩了。

構(gòu)造函數(shù)注入

當(dāng)想要通過構(gòu)造函數(shù)注入時附帽,需要在Bean中實(shí)現(xiàn)相應(yīng)的構(gòu)造函數(shù),并以想要注入的屬性為參數(shù)井誉。
Bean的代碼如下蕉扮。

public class Car{
    private int maxSpeed;
    private String brand;
    public Car(int maxSpeed,String brand){...};
}

然后我們在XML文件中進(jìn)行配置。

<bean id="car" class="Car">
  <constructor-arg type="java.lang.String">
        <value>紅旗</value>
  </constructor-arg>
  <constructor-arg type="double">
        <value>200</value>
  </constructor-arg>
</bean>

在通過構(gòu)造器注入時颗圣,配置文件中arg的順序與構(gòu)造器中的參數(shù)順序無關(guān)喳钟,當(dāng)只有一個構(gòu)造器的情況下上述配置文件才會生效屁使。因此建議使用索引匹配入?yún)ⅲ?code><constructor-arg index="0" value="紅旗">奔则。
當(dāng)兩個構(gòu)造器僅有intdouble的區(qū)別(如下)蛮寂,則此時還需要在配置文件中加上參數(shù)類型以作區(qū)分,即<constructor-arg index="0" type="int" value="200"/>易茬。

public class Car{
    private int maxSpeed;
    private double averageSpeed;
    private String brand;
    public Car(int maxSpeed,String brand){...};
    public Car(double averageSpeed,String brand){...};
}

如果構(gòu)造函數(shù)的參數(shù)的類型是可以辨別的(非基礎(chǔ)數(shù)據(jù)類型且入?yún)㈩愋透鳟悾?/strong>酬蹋,則可以不提供類型和索引的信息。
構(gòu)造器注入可能會出現(xiàn)循環(huán)依賴的問題抽莱,即A類需要注入B類范抓,B類需要注入A類,在這種情況下岸蜗,使用屬性注入就可以解決了尉咕。

工廠方法注入

在使用框架的過程中很少會使用到工廠方法注入,以下僅舉2個例子璃岳。

  1. 非靜態(tài)工廠類
public class CarFactory{
    public Car createHongQiCar(){}
}
<bean id="carFactory" class="CarFactory"/>

<bean id="car" factory-bean="carFactory" factory-method="createHongQiCar"/>

由于工廠類不是靜態(tài)的年缎,因此需要先定義工廠類的bean。

  1. 靜態(tài)工廠類
public class CarFactory{
    public static Car createHongQiCar(){}
}
<bean id="car" class="CarFactory" factory-method="createCar"/>

Bean的配置方式

配置Bean可以通過XML铃慷、注解单芜、Java類和Groovy DSL這四種方式,下面來詳細(xì)介紹各個配置方法的細(xì)節(jié)犁柜。

基于XML的配置

對于基于XML的配置洲鸠,Spring2.0以后采用Schema格式,使得配置文件更具擴(kuò)展性馋缅,但文件頭聲明會復(fù)雜一些扒腕,下面是一個例子。

<?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:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation=
  "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"
>
    <!-- 默認(rèn)命名空間的配置 -->
    <bean id="foo" class="com.smart.Foo"/>

    <!-- aop命名空間的配置 -->
    <aop:config>
        <aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>
    </aop:config>
</beans>

在上面的代碼中定義了3個命名空間:

  1. xmlns="http://www.springframework.org/schema/beans"萤悴,默認(rèn)命名空間:沒有空間名瘾腰,用于Spring Bean的定義。
  2. xsi標(biāo)準(zhǔn)命名空間:這個命名空間用于指定自定義命名空間的Schema樣式文件覆履,是W3C定義的標(biāo)準(zhǔn)命名空間蹋盆。
  3. xmlns:aop="http://www.springframework.org/schema/aop",aop命名空間:這個命名空間是Spring配置aop的命名空間硝全,即一種自定義的命名空間栖雾。

命名空間的定義分為兩個步驟:

  1. 第一步指定命名空間的名稱,如xmlns:aop="http://www.springframework.org/schema/aop"伟众。aop為命名空間的別名析藕,而"http://www.springframework.org/schema/aop"是命名空間的全限定名,習(xí)慣上用文檔發(fā)布機(jī)構(gòu)的官方網(wǎng)站和相關(guān)網(wǎng)站目錄作為全限定名赂鲤。如果命名空間的別名為空噪径,則表示該命名空間為文檔默認(rèn)的命名空間柱恤。
  2. 第二步指定命名空間的Schema文檔格式文件的位置,用空格或回車換行進(jìn)行分隔找爱。定義的語法如下<命名空間1> <命名空間1Schema文件> <命名空間2> <命名空間2Schema文件>(注意之間的分隔符可以為空格或換行符)梗顺。Schema地址有2個用途:一是XML解析器可以獲取Schema文件并對文檔進(jìn)行格式合法性驗(yàn)證;二是IDE可以引用Schema文件對文檔編輯提供自動補(bǔ)全功能车摄。

以上就是一個XML配置文件的結(jié)構(gòu)介紹寺谤,接下來將介紹如何對Bean進(jìn)行定制。

  • 字面值
    對于基本類型或其封裝類吮播,我們在XML中可以直接進(jìn)行設(shè)置变屁。對于字符串來說,如果其中包含了&意狠、<粟关、>、"环戈、'這5種特殊字符闷板,可以通過下面的![CDATA[]]進(jìn)行包裝,使得XML解析器將其中的內(nèi)容當(dāng)成純文本院塞;或者可以通過轉(zhuǎn)義序列來表示&amp遮晚、&lt、&gt拦止、&quot县遣、&apos。
    <bean id="car" class="Car">
     <property name="maxSpeed">
         <value>200</value>
     </property>
     <property name="brand">
         <value><![CDATA[紅旗&CA72]]></value>
     </property>
    </bean>
    
  • 引用其他bean
    可以通過以下3種標(biāo)簽對其他的bean進(jìn)行引用汹族。
    1. bean:可以引用同一容器或父容器總的Bean萧求,這是最常見的形式。
    2. local:只引用同一配置文件中的Bean顶瞒。
    3. parent:只引用父容器中的Bean饭聚。
    <!--通過bean-->
    <bean id="car" class="Car"/>
    <bean id="boss" class="Boss">
      <property name="car">
        <ref bean="car"/>
      </property>
    </bean>
    <!--通過local與通過bean的方式類似-->
    <!--通過parent-->
    <!--在父容器中定義car-->
    <bean id="car" class="Car"/>
    <!--在子容器中定義另一個car-->
    <bean id="car" class="Car"/>
    <bean id="boss" class="Boss">
      <ref parent="car"><!--將引用父容器中的car-->
    </bean>
    
  • 內(nèi)部bean
    我們也可以通過隱藏類那樣定義bean。
    <bean id="boss" class="Boss">
      <property name="car">
        <bean class="Car">
          <property name="brand" value="紅旗"/>
        </bean>
      </property>
    </bean>
    
  • null值
    如果想要注入null值搁拙,需要顯示的將值設(shè)為<null/>,即<property name="brand"><value><null/></value></property>法绵。
  • 級聯(lián)屬性
    <bean id="boss" class="Boss">
      <property name="car.brand" value="紅旗"/>
    </bean>
    
    如果想要通過這種方式直接對boss中的car的屬性進(jìn)行設(shè)置箕速,則需要在Boss類中聲明一個初始化對象并實(shí)現(xiàn)getter()方法。
    public class Boss{
      private Car car=new Car();
      public Car getCar(){return car;}
    }
    
  • 集合類
    1. List
    <bean id="boss" class="Boss">
      <property name="favorites">
        <list>
          <value>看報(bào)</value>
          <value>滑雪</value>
        </list>
      </property>
    </bean>
    
    如果List的屬性類型可以通過字符串字面值進(jìn)行配置朋譬,那么就可以使用這種方式盐茎,如String[]int[]等徙赢。
    此外字柠,List還可以通過<ref>注入容器中其他的Bean探越。
    1. Set
    <bean id="boss" class="Boss">
      <property name="favorites">
        <set>
          <value>看報(bào)</value>
          <value>滑雪</value>
        </set>
      </property>
    </bean>
    
    1. Map
    <bean id="boss" class="Boss">
      <property name="jobs">
        <map>
          <entry>
            <key><value>AM</value><key>
            <value>會見客戶</value>
          </entry>
          <entry>
            <key><value>PM</value><key>
            <value>開會</value>
          </entry>
          <!--如果鍵值對都是對象-->
          <entry>
            <key><ref bean="keyBean"/><key>
            <ref bean="valueBean"/>
          </entry>
        </map>
      </property>
    </bean>
    
  • Properties
    Properties屬性可以看成鍵值都是字符串的Map類型。
    <bean id="boss" class="Boss">
      <property name="jobs">
        <props>
          <prop key="mail">123@gmail.com</prop>
        </props>
      </property>
    </bean>
    
  • 強(qiáng)類型集合
    Spring配置強(qiáng)類型和非強(qiáng)類型集合相同窑业,會將值自動轉(zhuǎn)換為目標(biāo)類型钦幔。
    public class Car{
      private Map<Integer,String> passengers=new HashMap<Integer,String>();
    }
    
  • 集合合并
    <bean id="boss1" class="Boss">
     <property name="favorites">
       <set>
         <value>看報(bào)</value>
       </set>
     </property>
    </bean>
    <bean id="boss2" class="Boss" parent="boss1">
     <property name="favorites">
       <set merge="true"> <!--合并父類中的同名set-->
         <value>看報(bào)</value>
       </set>
     </property>
    </bean>
    
  • 配置集合類型的Bean
    如果想要配置集合類型的Bean,而不是屬性類型的集合常柄,可以通過在Spring配置文件中引入util命名空間的聲明鲤氢,然后進(jìn)行配置。
    <beans
         xmlns:util="http://www.springframework.org/schema/util">
         xsi:shcemaLocation="http://www.springframework.org/schema/util
                                            http://www.springframework.org/schema/util/spring-util-4.0.xsd"
     <util:list id="favorite" list-class="java.util.LinkedList">
       <value>喝茶</value>
       <value>看報(bào)</value>
     </util:list>
    </beans>
    
簡化XML配置方式
  1. 字面值屬性
類型 簡化前 簡化后
字面值屬性 <property name="maxSpeed"><value>200</value></property> <property name="maxSpeed" value="200"/>
構(gòu)造函數(shù)參數(shù) <constructor-arg index="0"><value>200</value></constructor-arg> <constructor-arg index="0" value="200"/>
集合元素 <map>
<entry>
<key><value>AM</value></key>
<value>見客戶</value>
</entry>
</map>
<map>
<entry key="AM" value="見客戶"/>
</map>
  1. 引用對象屬性
類型 簡化前 簡化后
字面屬性值 <property name="car"> <ref-bean="car"/></property> <property name="car" ref="car">
構(gòu)造函數(shù) <constructor-arg> <ref-bean="car"></property> <constroctor-arg ref="car"/>
集合元素 <entry>
<key><ref bean="keyBean"/></key>
<ref bean="valueBean">
</entry>
<entry key-ref="keyBean" value-ref="valueBean"/>

<ref>的簡化形式對應(yīng)于<ref bean="xxx">西潘,而<ref local>和<ref parent>沒有對應(yīng)的簡化形式卷玉。

  1. 使用p命名空間
<beans xmlns:p="http://www.springframework.org/schema/p"><!--聲明p命名空間-->
  <bean id="car" class="Car"
    p:brand="紅旗"
    p:maxSpeed="200"/>
  <bean id="boss" class="Boss"
    p:car-ref="car"/>
</beans>

基于注解的配置

采用基于注解的配置文件,則Bean定義信息通過在Bean實(shí)現(xiàn)類上標(biāo)注注解實(shí)現(xiàn)喷市。

//這里定義了一個Dao的Bean
/*
  與@Component功能相似的還有:
    @Repository:用于對DAO實(shí)現(xiàn)類進(jìn)行標(biāo)注
    @Service:用于對Service實(shí)現(xiàn)類進(jìn)行標(biāo)注
    @Controller:用于對Controller實(shí)現(xiàn)類進(jìn)行標(biāo)注
*/
@Component("carDao")    
public class CarDao{
  //..
}

對于通過注解定義的bean需要在Spring配置文件中進(jìn)行額外設(shè)置相种。

<beans
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:"http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd"
>
  <!--掃描類包以應(yīng)用注解的bean,可以通過resource-pattern進(jìn)行過濾 -->
  <!-- 其余過濾的方法還有include-filter和exclude-filter -->
  <context:component-scan base-package="package" resource-pattern="./*.class">
</beans>

Bean完成配置后品姓,還需要通過注解進(jìn)行自動注入

@Service
public class LoginService{
  //注入LogDao的bean
  //對required=false設(shè)置寝并,當(dāng)Spring啟動時如果未找到對應(yīng)的bean則不會報(bào)錯
  //通過Qualifier可以指定對應(yīng)bean的名稱
  @Autowired(required=false)
  @Qualifier("logDao")
  private LogDao logDao;
  
  //對類方法進(jìn)行標(biāo)注
  @Autowired
  @Qualifier("logDao")
  public void setLogDao(LogDao logDao){}
  //或者通過這種形式
  public void setLogDao(@Qualifier("logDao")LogDao logDao){}

  //如果對類中集合類的變量或方法入?yún)⑦M(jìn)行標(biāo)注,那么Spring會將容器中類型匹配的所有Bean都注入
  @Autowired
  private List<Plugin> plugins;
  //Spring如果發(fā)現(xiàn)變量是一個list和一個map缭黔,會將容器中匹配集合元素類型的所有bean都注入
  //這里將會把plugins的bean注入map集合食茎,key是bean的名字,value是所有實(shí)現(xiàn)了plugin的bean馏谨。
  @Autowired
  private Map<String,Plugin> pluginMaps别渔;
  //如果Plugin有多個實(shí)現(xiàn)類,那么可以在不同的實(shí)現(xiàn)類前用@Order(value=1)對注入順序進(jìn)行設(shè)置惧互,越小越先加載
}

基于Java類的配置哎媚、基于Groovy DSL的配置

一般來說,使用XML和標(biāo)注的方式就能解決幾乎所有的任務(wù)喊儡。建議使用XML配置DataSource拨与、SessionFactory等資源bean,在XML中利用aop艾猜、context命名空間進(jìn)行相關(guān)主題的配置买喧,其余所有項(xiàng)目中開發(fā)的Bean都通過基于注解配置的方式進(jìn)行配置。

Bean基本配置

Bean的命名

Bean的id屬性命名與Java變量的命名要求相同匆赃,而name屬性命名沒有任何字符上的限制淤毛。可以通過不設(shè)置id屬性命名來實(shí)例化匿名Bean算柳。

<bean class="Car"/>
<bean class="Car"/>
<bean class="Car"/>

這樣就實(shí)例化了3個匿名Bean低淡,第一個Bean通過getBean("Car")獲得,第二個通過getBean("Car#1")獲得。

依賴注入

Spring支持屬性注入和構(gòu)造函數(shù)注入蔗蹋,除此之外還支持工廠法注入方式何荚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市猪杭,隨后出現(xiàn)的幾起案子餐塘,更是在濱河造成了極大的恐慌,老刑警劉巖胁孙,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阻肿,死亡現(xiàn)場離奇詭異裳涛,居然都是意外死亡雅镊,警方通過查閱死者的電腦和手機(jī)啤誊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來狂票,“玉大人候齿,你說我怎么就攤上這事」胧簦” “怎么了慌盯?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長掂器。 經(jīng)常有香客問我亚皂,道長,這世上最難降的妖魔是什么国瓮? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任灭必,我火速辦了婚禮,結(jié)果婚禮上乃摹,老公的妹妹穿的比我還像新娘禁漓。我一直安慰自己,他們只是感情好孵睬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布播歼。 她就那樣靜靜地躺著,像睡著了一般掰读。 火紅的嫁衣襯著肌膚如雪秘狞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天蹈集,我揣著相機(jī)與錄音谒撼,去河邊找鬼。 笑死雾狈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抵皱。 我是一名探鬼主播善榛,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辩蛋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了移盆?” 一聲冷哼從身側(cè)響起悼院,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咒循,沒想到半個月后据途,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叙甸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年颖医,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裆蒸。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡熔萧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出僚祷,到底是詐尸還是另有隱情佛致,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布辙谜,位于F島的核電站俺榆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏装哆。R本人自食惡果不足惜罐脊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望烂琴。 院中可真熱鬧爹殊,春花似錦、人聲如沸奸绷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽号醉。三九已至反症,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間畔派,已是汗流浹背铅碍。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留线椰,地道東北人胞谈。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親烦绳。 傳聞我的和親對象是個殘疾皇子卿捎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355

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