1. 程式人生 > >基於註解自動裝配Bean

基於註解自動裝配Bean

      自動裝配(autowiring):有助於減少<property>和<constructor-arg>,讓spring自動識別如何裝配Bean的依賴關係。

      自動檢測(autodiscovery):讓spring自動識別那個類要被裝配成spring Bean,減少對<bean>元素的使用。

1.自動裝配Bean屬性

1.1    4中型別的自動裝配

      1.byName:把與Bean的屬性具有相同名字(或者ID)的其他Bean自動裝配到Bean的對應屬性中。如果沒有與屬性的名字相匹配的Bean,則該屬性不進行裝配。

      2.byType:把與Bean的屬性具有相同型別的其他Bean自動裝配到Bean的對應屬性中。如果沒有與屬性的型別相匹配的Bean,則該屬性不進行裝配。

      3.constructor:把與Bean的構造器入參具有相同型別的其他Bean自動裝配到Bean構造器的對應入參中。

      4.autodetect:先按constructor來裝配,失敗了按byType來裝配。

1.1.1  byName自動裝配

<bean id="aaa" clas=""/>
<bean id="bbb" class="" >
   <property name="aaa" ref="aaa"/>
</bean>

如果bbb中aaa屬性名字和Bean的id相同,則可以自動裝配。如果bean的id和property的name相同,那麼可以變為下面的這種方式:

<bean id="aaa" clas=""/>
<bean id="bbb" class="" autowire="byName">
 
</bean>

如果一個Bean中屬性和其他Bean的id相同就會自動裝配,可是自己不需要自動裝配。byName的缺點就是要假設屬性名和Bean的id要一樣。

1.1.2  byType自動裝配

      跟byName一樣,只是ByType不去找屬性名一樣,而是去找屬性的型別。

<bean id="aaa" clas="A"/>
<bean id="bbb" class="" >
   <property name="aaa" ref="aaa"/>
</bean>
如果bbb中屬性aaa為A型別,則可以byType自動裝配,把autowire="byType"
<bean id="aaa" clas="A"/>
<bean id="bbb" class="" autowire="ByType">
   
</bean>
      如果byType找到多個Bean,那麼丟擲異常,應用只允許存在一個Bean與需要的自動裝配的屬性相匹配。byName不會找到多個,因為Bean的id是不一樣的。解決的辦法就是可以標識一個首選Bean,也可以讓其他Bean失去資格。<bean>元素有個primary屬性表示首選Bean,但是預設為true,所有的Bean都是首選Bean,所以要把非首選的Bean設定為false。<bean>的

autowire-candidate屬性可以設定為false表示自動裝備忽略Bean的資格。

1.1.3 constructor自動裝配

      不需要<constructor-arg>元素,autowire為constructor。和byType有相同的侷限性,也是按照型別去匹配的,一個構造器引數對應多個Bean,還有一個Bean對應多個構造器。

1.2 預設自動裝配

      如果所有的bean都按照同一型別自動裝配,可以再<beans>元素中加default-autowire屬性。這個屬性預設為none,表示不使用自動裝配。可以設定為byName等型別。<bean>中的autowire會覆蓋default-autowire屬性。<property>會覆蓋自動裝配的值。

      autowire=“constructor”時,不能與<constructor-arg>同時存在。其他型別可以於<property>同時存在。

2.  使用註解裝配

      spring容器是預設禁用註解裝配的。要啟動,最簡單的就是context名稱空間的<context:annotation-config/>

      1.spring自帶的@Autowired註解

      2.JSR-330的@Inject註解

      3.JSR-250的@Resource註解

2.1 @Autowired

      有了這個註解,spring會按byType自動裝配。這個註解可以加在setter方法上,還可以加在需要自動裝配Bean的任意方法上,還可以加在構造器上。這個註解可以直接加在屬性上,並刪除setter方法。

       這個註解必須只能有一個Bean匹配到註解的引數或屬性中。沒有匹配Bean或匹配多個Bean會有問題。

2.1.1可選的自動裝配

       預設情況下,這個註解標識的屬性或引數必須是可裝配的。沒有Bean裝配到,就會報NoSuchBeanDefinitionException。這個時候可以設定required=false來設定自動裝配是可選的。沒有匹配到Bean就會為null。

@Autowired(required=false)
private A a;
       required可以用於@Autowired使用的任何地方,但是在構造器中,只能有一個構造器是required為true,其他都要設定為false。當@Autowired標註多個構造器時,spring會從滿足條件的構造器中選擇入參最多的構造器。

2.1.2限定歧義性的依賴
        有可能spring找到了多個滿足條件的Bean,可以使用@Qualifier註解。

@Autowired
@Qualifier("a")//指定a,預設從id找
private A a;
        相當於把byType轉為了byName。縮小了自動裝配Bean的範圍。還可以在Bean中宣告
<bean class="A">
      <qualifier value="a"/>//可以限定這個Bean為a
</bean>
@Qualifier("a")//可以限定這個Bean為a
class A implement B{}
        @Autowired是減少spring xml配置的一種方式。但是使用它的類會引入spring的特定依賴。

2.2 @Inject
       

@Inject
private A a;
       這個註解和@Autowired一樣可以自動裝配,可以裝配屬性,方法,構造器。但是沒有required屬性所以裝配的Bean必須存在,不存在會報錯。

       
2.2.1限定@Inject所標註的屬性

       @Autowired的@Qualifier與@Inject的@Named對應

@Inject
@Named("a")
private A a;
      @Qualifier註解縮小Bean的選擇範圍(預設使用Bean的id),@Named通過Bean的Id標識可選擇的Bean。

2.3在註解注入中使用表示式

        @Value可以裝配簡單值。

@Value("jack")//這裡面是一個表示式
private String name;
@Value("#{abc.name}")
private String name;

[email protected]

@Resource裝配順序
  1. 如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則丟擲異常
  2. 如果指定了name,則從上下文中查詢名稱(id)匹配的bean進行裝配,找不到則丟擲異常
  3. 如果指定了type,則從上下文中找到型別匹配的唯一bean進行裝配,找不到或者找到多個,都會丟擲異常
  4. 如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;如果沒有匹配,則回退為一個原始型別進行匹配,如果匹配則自動裝配;

3.自動檢測Bean

       <context:component-scan>除了完成<context:annotation-config>一樣的工作外,還允許Spring自動檢測Bean和定義Bean。

<context:component-scan//替代了<context:annotation-config>
base-package="包">//會掃描指定的包及其子包,並找出能夠自動註冊的spring Bean
     
</context:component-scan>
        


3.1為自動檢測標註Bean

      預設情況下<context:component-scan>查詢使用構造型註解所標註的類。

      [email protected]:通用的構造型註解,表示該類為spring元件

      [email protected]:表示該類定義為spring mvc controller

      [email protected]:表示該類為資料倉庫。

      [email protected]:表示該類定義為服務

      5.使用@Component標識的任意自定義註解
         

3.2過濾元件掃描

       <context:component-scan>下面還有子元素<context:include-filter>和<context:exclude-filter>。只是用<context:component-scan>的情況下,spring只會去找基於註解的元件。但是還要包含一個沒有註解的介面的所有實現類要怎麼辦。就是用<context:include-filter>

<context:component-scan
base-package="包">
     <context:include-filter type="assignable" expression="xxx.abc"/>
</context:component-scan>
type的5中型別

1.annotation:掃面指定註解所標註的類,通過expression指定註解。

2.assignable:掃面派生於expression指定型別的哪些類。

3.aspectj:掃面與expression指定的aspectJ表示式匹配的類

4.custom:指定expression使用的自定義TypeFilter實現類。

5.regex:正則匹配的類。

4 使用spring基於Java的配置

4.1 建立基於Java的配置

      <context:component-scan>也會自動載入使用@Configuration註解所標註的類。

4.2 定義一個配置類

      @Configurstion標註的類相當於<Beans>元素。可以包含一個或多個Bean。這些Bean的定義是使用@Bean註解來標註的方法。

4.3 宣告一個簡單Bean

@Bean 
public A get(){
    return new B();
}
     @Bean告知spring返回一個物件,該物件應該被註冊為spring上下文的一個Bean。方法名為Bean的id。
      相對於xml配置來說的一個優點就是,xml是用string型別配置的,編譯期無法檢查。如果重新命名了一個類,或許會完了修改xml配置。

4.4 使用spring的基於Java的配置進行注入

 簡單值注入:

@Bean
public A get(){
      return new B(12);
}
@Bean
public A get(){
      B b =  new B();
      b.setName("jack");
       return B;
}
引用注入:
@Bean
public A get(){
      return new B();
}
@Bean
public C set(){
      return new C(get());
}
這裡呼叫get()不會呼叫get()方法而是呼叫spring上下文中的Bean。