Spring-IoC中裝配Bean

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

依賴注入

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

屬性注入

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

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

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

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

這樣設(shè)置完成后,當Spring啟動后,就會自動生成idcar,classCar,屬性分別為200紅旗CA72Bean
對于屬性的命名,要求變量的前兩個字母要么全部大寫,要么全部小寫,iCCard、iDCode是非法的。如果取非法的變量名,在試圖啟動Spring時,將會失敗。因此命名的建議是像QQ、MSN、ID等正常以大寫字母出現(xiàn)的專業(yè)術(shù)語,在Java中一律使用小寫形式。

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

當想要通過構(gòu)造函數(shù)注入時,需要在Bean中實現(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文件中進行配置。

<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),當只有一個構(gòu)造器的情況下上述配置文件才會生效。因此建議使用索引匹配入?yún)ⅲ?code><constructor-arg index="0" value="紅旗">。
當兩個構(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這四種方式,下面來詳細介紹各個配置方法的細節(jié)。

基于XML的配置

對于基于XML的配置,Spring2.0以后采用Schema格式,使得配置文件更具擴展性,但文件頭聲明會復雜一些,下面是一個例子。

<?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"
>
    <!-- 默認命名空間的配置 -->
    <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",默認命名空間:沒有空間名,用于Spring Bean的定義。
  2. xsi標準命名空間:這個命名空間用于指定自定義命名空間的Schema樣式文件,是W3C定義的標準命名空間。
  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"是命名空間的全限定名,習慣上用文檔發(fā)布機構(gòu)的官方網(wǎng)站和相關(guān)網(wǎng)站目錄作為全限定名。如果命名空間的別名為空,則表示該命名空間為文檔默認的命名空間。
  2. 第二步指定命名空間的Schema文檔格式文件的位置,用空格或回車換行進行分隔。定義的語法如下<命名空間1> <命名空間1Schema文件> <命名空間2> <命名空間2Schema文件>(注意之間的分隔符可以為空格或換行符)。Schema地址有2個用途:一是XML解析器可以獲取Schema文件并對文檔進行格式合法性驗證;二是IDE可以引用Schema文件對文檔編輯提供自動補全功能。

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

  • 字面值
    對于基本類型或其封裝類,我們在XML中可以直接進行設(shè)置。對于字符串來說,如果其中包含了&、<、>、"、'這5種特殊字符,可以通過下面的![CDATA[]]進行包裝,使得XML解析器將其中的內(nèi)容當成純文本;或者可以通過轉(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種標簽對其他的bean進行引用。
    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的屬性進行設(shè)置,則需要在Boss類中聲明一個初始化對象并實現(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>看報</value>
          <value>滑雪</value>
        </list>
      </property>
    </bean>
    
    如果List的屬性類型可以通過字符串字面值進行配置,那么就可以使用這種方式,如String[]、int[]等。
    此外,List還可以通過<ref>注入容器中其他的Bean。
    1. Set
    <bean id="boss" class="Boss">
      <property name="favorites">
        <set>
          <value>看報</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>
    
  • 強類型集合
    Spring配置強類型和非強類型集合相同,會將值自動轉(zhuǎn)換為目標類型。
    public class Car{
      private Map<Integer,String> passengers=new HashMap<Integer,String>();
    }
    
  • 集合合并
    <bean id="boss1" class="Boss">
     <property name="favorites">
       <set>
         <value>看報</value>
       </set>
     </property>
    </bean>
    <bean id="boss2" class="Boss" parent="boss1">
     <property name="favorites">
       <set merge="true"> <!--合并父類中的同名set-->
         <value>看報</value>
       </set>
     </property>
    </bean>
    
  • 配置集合類型的Bean
    如果想要配置集合類型的Bean,而不是屬性類型的集合,可以通過在Spring配置文件中引入util命名空間的聲明,然后進行配置。
    <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>看報</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實現(xiàn)類上標注注解實現(xiàn)。

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

對于通過注解定義的bean需要在Spring配置文件中進行額外設(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進行過濾 -->
  <!-- 其余過濾的方法還有include-filter和exclude-filter -->
  <context:component-scan base-package="package" resource-pattern="./*.class">
</beans>

Bean完成配置后,還需要通過注解進行自動注入

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

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

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

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

Bean基本配置

Bean的命名

Bean的id屬性命名與Java變量的命名要求相同,而name屬性命名沒有任何字符上的限制??梢酝ㄟ^不設(shè)置id屬性命名來實例化匿名Bean。

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

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

依賴注入

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容