1. 程式人生 > >Spring 裝配Bean

Spring 裝配Bean

spring 裝配bean

spring裝配bean的三種機制

  • 在XML中進行顯示配置
  • 在Java中進行顯示配置
  • 隱式的bean發現機制和自動裝配

自動化裝配bean

Spring從兩個角度來實現自動化裝配

  • 元件掃描:Spring會自動發現應用上下文中所建立的bean
  • 自動裝配:Spring自動滿足bean之間的依賴

Spring中有4種類型的元件自動掃描註釋型別

  • @Component – 指示自動掃描元件。
  • @Repository – 表示在持久層DAO元件。
  • @Service – 表示在業務層服務元件。
  • @Controller – 表示在表示層控制器元件。
開啟自動元件掃描

1 xml顯式配置

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:component-scan base-package="com.yiibai.customer" />

</beans>

2 註解式配置

@Configuration
@ComponentScan
public calss CDPlayerConfig(){

}

CDPlayerConfig中並沒有顯式地宣告任何bean,只不過它是用來@ComponentScan註解,這個註解能夠在spring中棄用元件掃描
如果沒有其他配置的話,@ComponentScan預設會掃描域配置類相同的包

無論註解式配置或者xml顯示配置,我們都可以明確地設定掃描的基礎班

<!-- 使用Annotation自動註冊Bean,只掃描@Controller -->
<!-- base-package 如果多個,用“,”分隔 -->
<context:component-scan base-package="com.digitalpublishing.sage.dc.controller" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
@ComponentScan(basePackages={"controller","service"})
建立可被發現的bean

建立POJO 加上註解@Component
元件掃描預設是不啟用的,我們需要顯示配置一下Spring,從而命令他去需找導遊@Component註解的類
,併為其建立bean

通過為bean添加註解實現自動裝配

@Autowired註解不僅能夠用在構造器上,還能用在屬性的Setter方法上
在spring初始化之後,它會盡可能去滿足bean的依賴,不管是構造器,setter方法還是在其他的方法,spring都會嘗試滿足方法引數上所宣告的依賴
假如有且只有一個bean匹配依賴需求的話,那麼這個bean將會被裝配進來
如果沒有匹配的bean,那麼在應用上下文建立的時候,spring會丟擲一個以上,為了避免異常的出現,你可以將@Autoeired的required屬性設定為false
但如果將required屬性設定為false時,spring會嘗試執行自動裝配,但是如果沒有匹配的bean的話,spring將會讓這個bean處於未裝配的狀態.如果在你的程式碼中沒有進行null檢查的話,這個處於未裝配狀態的屬性可能會導致空指標異常

儘管很多場景下通過元件掃描和自動裝配實現spring的自動化配置是更為推薦的方式,但如果你想要將第三方庫中的元件裝配到你的應用總,在這種情況下,是沒有辦法在它的類上新增@Component和@Autowired註解的,因此就不能使用自動化裝配的方案了

這種情況下,你必須要採用顯式裝配的方式,在顯式配置的時候,有兩種可選方案

  • java
  • xml

通過Java程式碼裝配bean

進行顯式配置是,JavaConfig是更好的方案,它更強大,型別安全並且對重構友好
因為它就是Java程式碼,就像應用程式中的其他Java程式碼一樣
但JavaConfig與其他的Java程式碼又有所區別,JavaConfig是配置大媽,這意味著它不應該包含任何業務邏輯,JavaConfig也不應侵入到業務邏輯程式碼中,其應放到單獨的保重,使它與其他的應用程式邏輯分離開來

建立配置類

建立配置類,為其新增@Configuration註解,@Configuration註解表明這個類是一個配置類,該類應該包含在spring應用上下文中如何建立bean的細節

宣告簡單的bean

要在JavaConfig中宣告bean,我們需要編寫一個方法,這個方法會建立所需型別的例項,然後給這個方法新增@Bean註解
@Bean註解會告訴spring這個方法將會返回一個物件,該物件要註冊為spring應用上下文中的bean,方法體中包含了最終產生bean例項的邏輯

@Configuration
public class CDPlayerConfig{
  @Bean
  public CompactDisc sgtPeppers(){
    return new SgtPeppers();
  }

}

藉助JavaConfig實現注入

@Configuration
public class CDPlayerConfig{
  @Bean
  public CompactDisc sgtPeppers(){
    return new SgtPeppers();
  }

  @Bean
  public CDPlayer cDPlayer(){
    return new CDPlayer()(sgtPeppers());
  }

}

cDPlayer()方法像sgtPeppers()方法一樣,同樣使用了@Bean註解,這表明這個方法會建立一個bean例項並將其註冊到spring應用上下文中,所建立的beanID為cdPlayer,與方法的名字相同
cDPlayer()的方法體與sgtPeppers()稍微有些區別,在這裡並沒有使用預設的構造器構建例項,而是呼叫了需要傳入CompactDisc物件的構建器來建立CDPlayer例項

看起來,CompactDisc是榮國呼叫sgtPeppers()得到的,但情況並非如此,因為sgtPeppers()方法上添加了@Bean註解,spring將會攔截所有對他的呼叫,並確保直接返回該方法所建立的bean,而不是每次都對其進行實際的呼叫

通過xml裝配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
                http://www.springframework.org/schema/context">


</beans>

宣告一個簡單的

<bean id="demoController" class="soundsystem.CDPlayer" />

這裡聲明瞭一個很簡單的bean,建立這個bean的類通過class屬性來指定的,並且要使用全限定的類名

藉助構造器注入初始化的bean

在springxml配置中,只有一種宣告bean的方式:使用

xml宣告DI時,具體到構造器注入,有樑總節本配置方案選擇

  • 使用spring3.0所引入的c-名稱空間
<bean id="cdPlayer" class="soundsystem.CDPlayer"
  <constructor-arg ref="copactDisc" />
</bean>

當spring遇到這個

c-名稱空間
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:c="http://www.springframework.org/schema/c"
    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">

    <bean id="cdPlayer" class="soundsystem.CDPlayer"
          c:cd-ref="compactDisc" />
</beans>

也可以直接注入值

將字面量注入到構造器中

我們不止可以將物件的引用裝配到依賴於它們的其他物件之中,而且可以用一個字面量值來配置物件
例如:

//POJO
public class BlankDisc {
  private String title;
  private String artist;

  public BlankDisc(String title,String artist){
    this.title = title;
    this.artist = artist;
  }

  public void play(){
    System.out.println("playing" + title + "by" ++ artist);
  }

}


<bean id="cdPlayer" class="soundsystem.CDPlayer" >
  <constructor-arg value="sgt.Pepper's lonely hearts clue band" />
  <constructor-arg value="The Beatles" />
</bean>

使用value屬性,通過該屬性表明給定的值要以字面量的形式注入到構造器中

c-名稱空間
第一種,引用構造器引數的名字

<bean id="demoController" class="soundsystem.CDPlayer" >
  <c:_title="sgt.Pepper's lonely hearts clue band" />
  <c:_artist=="The Beatles" />
</bean>

第二中,通過引數索引裝配相同的字面量值

<bean id="demoController" class="soundsystem.CDPlayer" >
  <c:_0="sgt.Pepper's lonely hearts clue band" />
  <c:_1=="The Beatles" />
</bean>

xml不允許摸個元素的多個屬性具有相同的名字,因此,如果有兩個或更多的構造器引數的話,我們不能簡單地使用下劃線進行標識.但是如果只有一個構造引數的話,就可以

裝配集合 c-名稱空間無法作答
//POJO
public class BlankDisc {
  private String title;
  private String artist;
  private List<String> tracks;

  public BlankDisc(String title,String artist){
    this.title = title;
    this.artist = artist;
    this.tracks = tracks;
  }

  public void play(){
    System.out.println("playing" + title + "by" ++ artist);
  }
}

<bean id="cdPlayer" class="soundsystem.CDPlayer" >
  <constructor-arg value="sgt.Pepper's lonely hearts clue band" />
  <constructor-arg value="The Beatles" />
  <constructor-arg><null/></constructor-arg>
</bean>

因為增加了一個tarcts屬性,在宣告bean的時候 我們必須給出宣告,最簡單的方法就是將列表設定為null,因為它是要給構造器引數,我們必須給出宣告,所以採用上述方式傳遞null給他
但更好的解決辦法是提供一個列表
例如:

<bean id="cdPlayer" class="soundsystem.CDPlayer" >
  <constructor-arg value="sgt.Pepper's lonely hearts clue band" />
  <constructor-arg value="The Beatles" />
  <constructor-arg>
    <list>
      <value>sgt.Pepper's lonely hearts clue band</value>
      <value>A</value>
      <value>B</value>
    </list>
  </constructor-arg>
</bean>

也可以用

<bean id="cdPlayer" class="soundsystem.CDPlayer" >
  <constructor-arg value="sgt.Pepper's lonely hearts clue band" />
  <constructor-arg value="The Beatles" />
  <constructor-arg>
    <list>
      <ref bean="sagtPepers"/>
      <ref bean="A"/>
      <ref bean="B"/>
    </list>
  </constructor-arg>
</bean>

設定屬性 (setter注入)

<bean id="cdPlayer" class="soundsystem.CDPlayer" >
  <property name="compactDisc" ref="compactDisc" />
</bean>
//<property>元素為屬性的setter方法提供的功能,與<constructor-arg>元素為構造器所提供的功能一樣
//在本例中,它引用了ID為compactDisc的bean(通過ref屬性),並將期注入到compactDisc屬性中(通過setCompactDisc()方法).