spring中的@Configration詳解

       雖然 2.0 版本發佈以來,Spring 陸續提供了十多個註解,但是提供的這些註解只是爲了在某些情況下簡化 XML 的配置,並非要取代 XML 配置方式。這一點可以從 Spring IoC 容器的初始化類可以看出:ApplicationContext 接口的最常用的實現類是 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext,以及面向 Portlet 的 XmlPortletApplicationContext 和麪向 web 的 XmlWebApplicationContext,它們都是面向 XML 的。Spring 3.0 新增了另外兩個實現類:AnnotationConfigApplicationContext 和 AnnotationConfigWebApplicationContext。從名字便可以看出,它們是爲註解而生,直接依賴於註解作爲容器配置信息來 源的 IoC 容器初始化類。由於 AnnotationConfigWebApplicationContext 是 AnnotationConfigApplicationContext 的 web 版本,其用法與後者相比幾乎沒有什麼差別,因此本文將以 AnnotationConfigApplicationContext 爲例進行講解。  
AnnotationConfigApplicationContext 搭配上 @Configuration 和 @Bean 註解,自此,XML 配置方式不再是 Spring IoC 容器的唯一配置方式。兩者在一定範圍內存在着競爭的關係,但是它們在大多數情況下還是相互協作的關係,兩者的結合使得 Spring IoC 容器的配置更簡單,更強大。  
之前,我們將配置信息集中寫在 XML 中,如今使用註解,配置信息的載體由 XML 文件轉移到了 Java 類中。我們通常將用於存放配置信息的類的類名以 “Config” 結尾,比如 AppDaoConfig.java、AppServiceConfig.java 等等。我們需要在用於指定配置信息的類上加上 @Configuration 註解,以明確指出該類是 Bean 配置的信息源。並且 Spring 對標註 Configuration 的類有如下要求:  
配置類不能是 final 的;配置類不能是本地化的,亦即不能將配置類定義在其他類的方法內部;配置類必須有一個無參構造函數。AnnotationConfigApplicationContext 將配置類中標註了 @Bean 的方法的返回值識別爲 Spring Bean,並註冊到容器中,受 IoC 容器管理。@Bean 的作用等價於 XML 配置中的 標籤。示例如下:  
@Configuration  
public class BookStoreDaoConfig{  
@Bean  
public UserDao userDao(){ return new UserDaoImpl();}  
@Bean  
public BookDao bookDao(){return new BookDaoImpl();}  
 
Spring 在解析到以上文件時,將識別出標註 @Bean 的所有方法,執行之,並將方法的返回值 ( 這裏是 UserDaoImpl 和 BookDaoImpl 對象 ) 註冊到 IoC 容器中。默認情況下,Bean 的名字即爲方法名。因此,與以上配置等價的 XML 配置如下: 


@Bean 具有以下四個屬性:  
name -- 指定一個或者多個 Bean 的名字。這等價於 XML 配置中 的 name 屬性。initMethod -- 容器在初始化完 Bean 之後,會調用該屬性指定的方法。這等價於 XML 配置中 的 init-method 屬性。destroyMethod -- 該屬性與 initMethod 功能相似,在容器銷燬 Bean 之前,會調用該屬性指定的方法。這等價於 XML 配置中 的 destroy-method 屬性。autowire -- 指定 Bean 屬性的自動裝配策略,取值是 Autowire 類型的三個靜態屬性。Autowire.BY_NAME,Autowire.BY_TYPE,Autowire.NO。與 XML 配置中的 autowire 屬性的取值相比,這裏少了 constructor,這是因爲 constructor 在這裏已經沒有意義了。@Bean 沒有直接提供指定作用域的屬性,可以通過 @Scope 來實現該功能,關於 @Scope 的用法已在上文列舉。  
下面講解基於註解的容器初始化。AnnotationConfigApplicationContext 提供了三個構造函數用於初始化容器。  
AnnotationConfigApplicationContext():該構造函數初始化一個空容器,容器不包含任何 Bean 信息,需要在稍後通過調用其 register() 方法註冊配置類,並調用 refresh() 方法刷新容器。AnnotationConfigApplicationContext(Class... annotatedClasses):這是最常用的構造函數,通過將涉及到的配置類傳遞給該構造函數,以實現將相應配置類中的 Bean 自動註冊到容器中。AnnotationConfigApplicationContext(String... basePackages):該構造函數會自動掃描以給定的包及其子包下的所有類,並自動識別所有的 Spring Bean,將其註冊到容器中。它不但識別標註 @Configuration 的配置類並正確解析,而且同樣能識別使用 @Repository、@Service、@Controller、@Component 標註的類。除了使用上面第三種類型的構造函數讓容器自動掃描 Bean 的配置信息以外,AnnotationConfigApplicationContext 還提供了 scan() 方法,其功能與上面也類似,該方法主要用在容器初始化之後動態增加 Bean 至容器中。調用了該方法以後,通常需要立即手動調用 refresh() 刷新容器,以讓變更立即生效。  
需要注意的是,AnnotationConfigApplicationContext 在解析配置類時,會將配置類自身註冊爲一個 Bean,因爲 @Configuration 註解本身定義時被 @Component 標註了。因此可以說,一個 @Configuration 同時也是一個 @Component。大多數情況下,開發者用不到該 Bean,並且在理想情況下,該 Bean 應該是對開發者透明的。@Configuration 的定義如下所示:  
@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Component  
public @interface Configuration {  
String value() default "";  
 
在一般的項目中,爲了結構清晰,通常會根據軟件的模塊或者結構定義多個 XML 配置文件,然後再定義一個入口的配置文件,該文件使用 將其他的配置文件組織起來。最後只需將該文件傳給 ClassPathXmlApplicationContext 的構造函數即可。針對基於註解的配置,Spring 也提供了類似的功能,只需定義一個入口配置類,並在該類上使用 @Import 註解引入其他的配置類即可,最後只需要將該入口類傳遞給 AnnotationConfigApplicationContext。具體示例如下:  
@Configuration  
@Import({BookStoreServiceConfig.class,BookStoreDaoConfig.class})  
public class BookStoreConfig{ … }  
混合使用 XML 與註解進行 Bean 的配置  
設計 @Configuration 和 @Bean 的初衷,並不是爲了完全取代 XML,而是爲了在 XML 之外多一種可行的選擇。由於 Spring 自發布以來,Spring 開發小組便不斷簡化 XML 配置,使得 XML 配置方式已經非常成熟,加上 Spring 2.0 以後出現了一系列命名空間的支持,使得 XML 配置方式成爲了使用簡單、功能強大的 Bean 定義方式。而且,XML 配置的一些高級功能目前還沒有相關注解能夠直接支持。因此,在目前的多數項目中,要麼使用純粹的 XML 配置方式進行 Bean 的配置,要麼使用以註解爲主,XML 爲輔的配置方式進行 Bean 的配置。  
之所以會出現兩者共存的情況,主要歸結爲三個原因:其一,目前絕大多數採用 Spring 進行開發的項目,幾乎都是基於 XML 配置方式的,Spring 在引入註解的同時,必須保證註解能夠與 XML 和諧共存,這是前提;其二,由於註解引入較晚,因此功能也沒有發展多年的 XML 強大,因此,對於複雜的配置,註解還很難獨當一面,在一段時間內仍然需要 XML 的配合才能解決問題。除此之外,Spring 的 Bean 的配置方式與 Spring 核心模塊之間是解耦的,因此,改變配置方式對 Spring 的框架自身是透明的。Spring 可以通過使用 Bean 後處理器 (BeanPostProcessor) 非常方便的增加對於註解的支持。這在技術實現上非常容易的事情。  
要使用混合配置方式,首先需要判斷以哪一種配置方式爲主。對這個問題的不同回答將會直接影響到實現的方式。然而大可不必爲此傷腦筋,因爲不論是以 XML 爲主,還是以註解爲主,配置方式都是簡單而且容易理解的。這裏不存在錯誤的決定,因爲僅僅是表現方式不一樣。我們首先假設以 XML 配置爲主的情況。  
對於已經存在的大型項目,可能初期是以 XML 進行 Bean 配置的,後續逐漸加入了註解的支持,這時我們只需在 XML 配置文件中將被 @Configuration 標註的類定義爲普通的 ,同時註冊處理註解的 Bean 後處理器即可。示例如下:  
// 假設存在如下的 @Configuration 類:  
package bookstore.config;  
import bookstore.dao.*;  
@Configuration  
public class MyConfig{  
@Bean  
public UserDao userDao(){  
return new UserDaoImpl();  
 
 
此時,只需在 XML 中作如下聲明即可:  

……  



由於啓用了針對註解的 Bean 後處理器,因此在 ApplicationContext 解析到 MyConfig 類時,會發現該類標註了 @Configuration 註解,隨後便會處理該類中標註 @Bean 的方法,將這些方法的返回值註冊爲容器總的 Bean。  
對於以上的方式,如果存在多個標註了 @Configuration 的類,則需要在 XML 文件中逐一列出。另一種方式是使用前面提到的自動掃描功能,配置如下:  

如此,Spring 將掃描所有 demo.config 包及其子包中的類,識別所有標記了 @Component、@Controller、@Service、@Repository 註解的類,由於 @Configuration 註解本身也用 @Component 標註了,Spring 將能夠識別出 @Configuration 標註類並正確解析之。  
對於以註解爲中心的配置方式,只需使用 @ImportResource 註解引入存在的 XML 即可,如下所示:  
@Configuration  
@ImportResource(“classpath:/bookstore/config/spring-beans.xml”)  
public class MyConfig{  
……  
 
// 容器的初始化過程和純粹的以配置爲中心的方式一致:  
AnnotationConfigApplicationContext ctx =  
new AnnotationConfigApplicationContext(MyConfig.class);  
……  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章