閱讀694 返回首頁    go 阿裏雲 go 技術社區[雲棲]


《Spring攻略(第2版)》——1.12 用@Autowired和@Resource自動裝配Bean

本節書摘來自異步社區《Spring攻略(第2版)》一書中的第1章,第1.12節,作者: 【美】Gary Mak , Josh Long , Daniel Rubio著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看

1.12 用@Autowired和@Resource自動裝配Bean

1.12.1 問題
在Bean配置文件中設置autowire屬性進行的自動裝配將裝配一個Bean的所有屬性。這樣的靈活性不足以僅僅裝配特定的屬性。而且,你隻能通過類型或者名稱自動裝配Bean。如果這兩種策略都不能滿足你的需求,就必須明確地裝配Bean。

1.12.2 解決方案
從Spring 2.5起,自動裝配功能進行了多處改進。你可以通過用@Autowired或者@Resource(在JSR-250:Java平台常見注解中定義)注解一個設值方法、構造程序、字段甚至任意方法自動裝配特定的屬性。這意味著你除了設置autowire屬性之外,還有一個能夠滿足需求的選擇。但是,這種基於注解的選項要求你使用Java 1.5或者更高版本。

1.12.3 工作原理
為了要求Spring自動裝配具有@Autowired或者@Resource注解的屬性,你必須在IoC容器中注冊一個AutowiredAnnotationBeanPostProcessor實例。如果你使用一個Bean工廠,就必須通過API注冊這個Bean後處理器,否則,你隻能在你的應用上下文裏聲明一個實例。

<bean  />

你也可以簡單地在Bean配置文件中包含context:annotation-config元素,這將自動注冊一個AutowiredAnnotationBeanPostProcessor實例。

<beans xmlns="https://www.springframework.org/schema/beans"
   xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="https://www.springframework.org/schema/context"
   xsi:schemaLocation="https://www.springframework.org/schema/beans
     https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     https://www.springframework.org/schema/context
     https://www.springframework.org/schema/context/spring-context-3.0.xsd">
   <context:annotation-config />
   ...
</beans>

自動裝配一個兼容類型的Bean
@Autowired可以應用到一個特定的需要Spring自動裝配的屬性。例如,你可以用@Autowired注解prefixGenerator屬性的設值方法。然後,Spring將試圖裝配一個類型與prefixGenerator兼容的Bean。

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {
   ...
   @Autowired
   public void setPrefixGenerator(PrefixGenerator prefixGenerator) {
     this.prefixGenerator = prefixGenerator;
   }
}

如果你在IoC容器中定義了一個與PrefixGenerator類型兼容的Bean,它將自動地設置到PrefixGenerator屬性上。

<beans ...>
   ...
   <bean 
     >
     <property name="initial" value="100000" />
     <property name="suffix" value="A" />
   </bean>

   <bean 
     >
     <property name="pattern" value="yyyyMMdd" />
   </bean>
</beans>

默認情況下,所有帶有@Autowired的屬性都是必需的。當Spring不能找到匹配的Bean進行裝配時,將會拋出一個異常。如果你希望某個屬性是可選的,將@Autowired的required屬性設置為false。之後,當Spring找不到匹配的Bean,將不設置該屬性。

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {
   ...
   @Autowired(required = false)
   public void setPrefixGenerator(PrefixGenerator prefixGenerator) {
     this.prefixGenerator = prefixGenerator;
   }
}

除了設值方法之外,@Autowired注解還可以應用到構造程序,Spring將為每個構造程序參數尋找一個具有兼容類型的Bean。

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {
   ...
   @Autowired
   public SequenceGenerator(PrefixGenerator prefixGenerator) {
     this.prefixGenerator = prefixGenerator;
   }
}

@Autowired注解還可以應用到一個字段,即使這個字段沒有聲明為Public。這樣,你不能省略這個字段的設值方法或者構造程序的聲明。Spring將通過反射把匹配的Bean注入這個字段。但是,用@Autowired注解非公開的字段將降低代碼的可測試性,因為代碼將很難進行單元測試(黑盒測試法無法使用模擬對象之類的方式操縱這一狀態)。

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

   @Autowired
   private PrefixGenerator prefixGenerator;
   ...
}

你甚至可以將@Autowired注解應用到具有任意名稱和任意數量參數的方法上,在這種情況下,Spring將試圖為每個方法參數裝配一個類型兼容的Bean。

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {
   ...
   @Autowired
   public void inject(PrefixGenerator prefixGenerator) {
     this.prefixGenerator = prefixGenerator;
   }
}

自動裝配所有兼容類型的Bean
@Autowired注解還可以應用到一個數組類型的屬性上,讓Spring自動裝配所有匹配的Bean。例如,你可以用@Autowired注解一個PrefixGenerator[]屬性。然後,Spring將一次性自動裝配所有類型與PrefixGenerator兼容的Bean。

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

   @Autowired
   private PrefixGenerator[] prefixGenerators;
   ...
}

如果你在IoC容器中有多個類型與PrefixGenerator兼容類型的Bean,它們將自動被添加到PrefixGenerators數組中。

<beans ...>
   ...
   <bean 
     >
     <property name="pattern" value="yyyyMMdd" />
   </bean>

   <bean 
     >
     <property name="pattern" value="yyyy" />
   </bean>
</beans>

相似地,你可以將@Autowired注解應用類型安全的集合。Spring能夠讀取這個集合的類型信息,自動裝配所有類型兼容的Bean。

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

   @Autowired
   private List<PrefixGenerator> prefixGenerators;
   ...
}

如果Spring注意到@Autowired注解應用到了一個關鍵字為字符串的類型安全java.util.Map,它將在這個Map中添加所有Bean名稱與關鍵字相同的兼容類型Bean。

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

   @Autowired
   private Map<String, PrefixGenerator> prefixGenerators;
   ...
}

使用限定符的按類型自動裝配
默認情況下,按照類型的自動裝配在IoC容器中有超過一個類型兼容的Bean時無效。但是,Spring允許你指定一個候選Bean,這個Bean的名稱在@Qualifier注解中提供。

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class SequenceGenerator {

   @Autowired
   @Qualifier("datePrefixGenerator")
   private PrefixGenerator prefixGenerator;
   ...
}

完成了這項工作,Spring將會試圖在IoC容器中查找一個具有這個名稱的Bean,將其裝配到這個屬性中。

<bean 
>
   <property name="pattern" value="yyyyMMdd" />
</bean>
@Qualifier注解也可以應用到方法參數中進行自動裝配。

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class SequenceGenerator {
   ...
   @Autowired
   public void inject(
        @Qualifier("datePrefixGenerator") PrefixGenerator prefixGenerator) {
     this.prefixGenerator = prefixGenerator;
   }
}

你可以為自動裝配創建一個自定義的限定符注解類型。這種注解類型必須用@Qualifier注解。如果你希望一種特殊的Bean和配置在注解裝飾字段或者設值方法時注入,那麼就可以使用這種注解類型。

package com.apress.springrecipes.sequence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;import
org.springframework.beans.factory.annotation.Qualifier;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER })
@Qualifier
public @interface Generator {

   String value();
}

之後,你可以將這個注解應用到@Autowired bean屬性。這將要求Spring自動裝配帶有這個限定符注解和特定值的Bean。

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

   @Autowired
   @Generator("prefix")
   private PrefixGenerator prefixGenerator;
   ...
}

你必須向希望自動裝配到前述的屬性中的目標Bean提供這個限定符。限定符由帶有type屬性的元素添加。限定符值在value屬性中指定。Value屬性映射到注解的String value()屬性。

<bean 
   >
   <qualifier type="Generator" value="prefix" />
   <property name="pattern" value="yyyyMMdd" />
</bean>

按照名稱自動裝配
如果你希望按照名稱自動裝配Bean屬性,可以用JSR-250 @Resource注解為一個設值方法、構造程序或者字段加上注解。默認情況下,Spring將試圖找到一個與屬性同名的Bean。但是你可以顯式地在name屬性中指定Bean名稱。

注:

為了使用JSR-250注解,你必須包含JSR 250依賴。如果你使用Maven,添加以下內容:

<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
package com.apress.springrecipes.sequence;

import javax.annotation.Resource;

public class SequenceGenerator {

   @Resource(name = "datePrefixGenerator")
   private PrefixGenerator prefixGenerator;
   ...
}

最後更新:2017-05-31 16:01:26

  上一篇:go  為什麼你的目標總達不成?
  下一篇:go  《Spring攻略(第2版)》——1.11 用XML配置自動裝配Bean