精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

詳解Spring3基于Annotation的依賴注入實現

開發(fā) 后端
本篇文章主要介紹Spring 的依賴配置方式與 Spring 框架的內核自身是松耦合設計的,由于文字比較多,所以分為兩部分,希望大家諒解。

簡介: Spring 的依賴配置方式與 Spring 框架的內核自身是松耦合設計的。然而,直到 Spring 3.0 以前,使用 XML 進行依賴配置幾乎是唯一的選擇。Spring 3.0 的出現改變了這一狀況,它提供了一系列的針對依賴注入的注解,這使得 Spring IoC 在 XML 文件之外多了一種可行的選擇。本文將詳細介紹如何使用這些注解進行依賴配置的管理。

使用 @Repository、@Service、@Controller 和 @Component 將類標識為 Bean

Spring 自 2.0 版本開始,陸續(xù)引入了一些注解用于簡化 Spring 的開發(fā)。@Repository 注解便屬于最先引入的一批,它用于將數據訪問層 (DAO 層 ) 的類標識為 Spring Bean。具體只需將該注解標注在 DAO 類上即可。同時,為了讓 Spring 能夠掃描類路徑中的類并識別出 @Repository 注解,需要在 XML 配置文件中啟用 Bean 的自動掃描功能,這可以通過 實現。如下所示:

// 首先使用 @Repository 將 DAO 類聲明為 Bean

  1. package bookstore.dao;   
  2. @Repository   
  3. public class UserDaoImpl implements UserDao{ …… }   

// 其次,在 XML 配置文件中啟動 Spring 的自動掃描功能

  1. <beans … >   
  2.     ……   
  3. <context:component-scan base-package=”bookstore.dao” />   
  4. ……   
  5. beans>  

如此,我們就不再需要在 XML 中顯式使用 進行 Bean 的配置。Spring 在容器初始化時將自動掃描 base-package 指定的包及其子包下的所有 class 文件,所有標注了 @Repository 的類都將被注冊為 Spring Bean。

為什么 @Repository 只能標注在 DAO 類上呢?這是因為該注解的作用不只是將類識別為 Bean,同時它還能將所標注的類中拋出的數據訪問異常封裝為 Spring 的數據訪問異常類型。 Spring 本身提供了一個豐富的并且是與具體的數據訪問技術無關的數據訪問異常結構,用于封裝不同的持久層框架拋出的異常,使得異常獨立于底層的框架。

Spring 2.5 在 @Repository 的基礎上增加了功能類似的額外三個注解:@Component、@Service、@Constroller,它們分別用于軟件系統(tǒng)的不同層次:

♦ @Component 是一個泛化的概念,僅僅表示一個組件 (Bean) ,可以作用在任何層次。

♦ @Service 通常作用在業(yè)務層,但是目前該功能與 @Component 相同。

♦ @Constroller 通常作用在控制層,但是目前該功能與 @Component 相同。

通過在類上使用 @Repository、@Component、@Service 和 @Constroller 注解,Spring 會自動創(chuàng)建相應的 BeanDefinition 對象,并注冊到 ApplicationContext 中。這些類就成了 Spring 受管組件。這三個注解除了作用于不同軟件層次的類,其使用方式與 @Repository 是完全相同的。

另外,除了上面的四個注解外,用戶可以創(chuàng)建自定義的注解,然后在注解上標注 @Component,那么,該自定義注解便具有了與所 @Component 相同的功能。不過這個功能并不常用。

當一個 Bean 被自動檢測到時,會根據那個掃描器的 BeanNameGenerator 策略生成它的 bean 名稱。默認情況下,對于包含 name 屬性的 @Component、@Repository、 @Service 和 @Controller,會把 name 取值作為 Bean 的名字。如果這個注解不包含 name 值或是其他被自定義過濾器發(fā)現的組件,默認 Bean 名稱會是小寫開頭的非限定類名。如果你不想使用默認 bean 命名策略,可以提供一個自定義的命名策略。首先實現 BeanNameGenerator 接口,確認包含了一個默認的無參數構造方法。然后在配置掃描器時提供一個全限定類名,如下所示:

  1. <beans ...>   
  2. <context:component-scan   
  3.     base-package="a.b" name-generator="a.SimpleNameGenerator"/>   
  4. beans>  

與通過 XML 配置的 Spring Bean 一樣,通過上述注解標識的 Bean,其默認作用域是"singleton",為了配合這四個注解,在標注 Bean 的同時能夠指定 Bean 的作用域,Spring 2.5 引入了 @Scope 注解。使用該注解時只需提供作用域的名稱就行了,如下所示:

  1. @Scope("prototype")   
  2. @Repository   
  3. public class Demo { … }  

如果你想提供一個自定義的作用域解析策略而不使用基于注解的方法,只需實現 ScopeMetadataResolver 接口,確認包含一個默認的沒有參數的構造方法。然后在配置掃描器時提供全限定類名:

  1. package="a.b"     
  2. scope-resolver="footmark.SimpleScopeResolver" />   

使用 @PostConstruct 和 @PreDestroy 指定生命周期回調方法

Spring Bean 是受 Spring IoC 容器管理,由容器進行初始化和銷毀的(prototype 類型由容器初始化之后便不受容器管理),通常我們不需要關注容器對 Bean 的初始化和銷毀操作,由 Spring 經過構造函數或者工廠方法創(chuàng)建的 Bean 就是已經初始化完成并立即可用的。然而在某些情況下,可能需要我們手工做一些額外的初始化或者銷毀操作,這通常是針對一些資源的獲取和釋放操作。Spring 1.x 為此提供了兩種方式供用戶指定執(zhí)行生命周期回調的方法。

第一種方式是實現 Spring 提供的兩個接口:InitializingBean 和 DisposableBean。如果希望在 Bean 初始化完成之后執(zhí)行一些自定義操作,則可以讓 Bean 實現 InitializingBean 接口,該接口包含一個 afterPropertiesSet() 方法,容器在為該 Bean 設置了屬性之后,將自動調用該方法;如果 Bean 實現了 DisposableBean 接口,則容器在銷毀該 Bean 之前,將調用該接口的 destroy() 方法。這種方式的缺點是,讓 Bean 類實現 Spring 提供的接口,增加了代碼與 Spring 框架的耦合度,因此不推薦使用。

第二種方式是在 XML 文件中使用 的 init-method 和 destroy-method 屬性指定初始化之后和銷毀之前的回調方法,代碼無需實現任何接口。這兩個屬性的取值是相應 Bean 類中的初始化和銷毀方法,方法名任意,但是方法不能有參數。示例如下:

  1. <bean id=”userService”   
  2. class=”bookstore.service.UserService”   
  3. init-method=”init” destroy-method=”destroy”>   
  4.     …   
  5. bean>  

Spring 2.5 在保留以上兩種方式的基礎上,提供了對 JSR-250 的支持。JSR-250 規(guī)范定義了兩個用于指定聲明周期方法的注解:@PostConstruct 和 @PreDestroy。這兩個注解使用非常簡單,只需分別將他們標注于初始化之后執(zhí)行的回調方法或者銷毀之前執(zhí)行的回調方法上。由于使用了注解,因此需要配置相應的 Bean 后處理器,亦即在 XML 中增加如下一行:

  1. <context:annotation-config />  

比較上述三種指定生命周期回調方法的方式,第一種是不建議使用的,不但其用法不如后兩種方式靈活,而且無形中增加了代碼與框架的耦合度。后面兩種方式開發(fā)者可以根據使用習慣選擇其中一種,但是最好不要混合使用,以免增加維護的難度。

使用 @Required 進行 Bean 的依賴檢查

依賴檢查的作用是,判斷給定 Bean 的相應 Setter 方法是否都在實例化的時候被調用了。而不是判斷字段是否已經存在值了。Spring 進行依賴檢查時,只會判斷屬性是否使用了 Setter 注入。如果某個屬性沒有使用 Setter 注入,即使是通過構造函數已經為該屬性注入了值,Spring 仍然認為它沒有執(zhí)行注入,從而拋出異常。另外,Spring 只管是否通過 Setter 執(zhí)行了注入,而對注入的值卻沒有任何要求,即使注入的 ,Spring 也認為是執(zhí)行了依賴注入。

標簽提供了 dependency-check 屬性用于進行依賴檢查。該屬性的取值包括以下幾種:

♦ none -- 默認不執(zhí)行依賴檢查。可以在 標簽上使用 default-dependency-check 屬性改變默認值。

♦ simple -- 對原始基本類型和集合類型進行檢查。

♦ objects -- 對復雜類型進行檢查(除了 simple 所檢查類型之外的其他類型)。

♦ all -- 對所有類型進行檢查。

舊版本使用 dependency-check 在配置文件中設置,缺點是粒度較粗。使用 Spring2.0 提供的 @Required 注解,提供了更細粒度的控制。@Required 注解只能標注在 Setter 方法之上。因為依賴注入的本質是檢查 Setter 方法是否被調用了,而不是真的去檢查屬性是否賦值了以及賦了什么樣的值。如果將該注解標注在非 setXxxx() 類型的方法則被忽略。

為了讓 Spring 能夠處理該注解,需要激活相應的 Bean 后處理器。要激活該后處理器,只需在 XML 中增加如下一行即可。

  1. <context:annotation-config/>  

當某個被標注了 @Required 的 Setter 方法沒有被調用,則 Spring 在解析的時候會拋出異常,以提醒開發(fā)者對相應屬性進行設置。

使用 @Resource、@Autowired 和 @Qualifier 指定 Bean 的自動裝配策略

自動裝配是指,Spring 在裝配 Bean 的時候,根據指定的自動裝配規(guī)則,將某個 Bean 所需要引用類型的 Bean 注入進來。 元素提供了一個指定自動裝配類型的 autowire 屬性,該屬性有如下選項:

♦ no -- 顯式指定不使用自動裝配。

♦ byName -- 如果存在一個和當前屬性名字一致的 Bean,則使用該 Bean 進行注入。如果名稱匹配但是類型不匹配,則拋出異常。如果沒有匹配的類型,則什么也不做。

♦ byType -- 如果存在一個和當前屬性類型一致的 Bean ( 相同類型或者子類型 ),則使用該 Bean 進行注入。byType 能夠識別工廠方法,即能夠識別 factory-method 的返回類型。如果存在多個類型一致的 Bean,則拋出異常。如果沒有匹配的類型,則什么也不做。

♦ constructor -- 與 byType 類似,只不過它是針對構造函數注入而言的。如果當前沒有與構造函數的參數類型匹配的 Bean,則拋出異常。使用該種裝配模式時,優(yōu)先匹配參數最多的構造函數。

♦ autodetect -- 根據 Bean 的自省機制決定采用 byType 還是 constructor 進行自動裝配。如果 Bean 提供了默認的構造函數,則采用 byType;否則采用 constructor 進行自動裝配。

當使用 byType 或者 constructor 類型的自動裝配的時候,自動裝配也支持引用類型的數組或者使用了泛型的集合,這樣,Spring 就會檢查容器中所有類型匹配的 Bean,組成集合或者數組后執(zhí)行注入。對于使用了泛型的 Map 類型,如果鍵是 String 類型,則 Spring 也會自動執(zhí)行裝配,將所有類型匹配的 Bean 作為值,Bean 的名字作為鍵。

我們可以給 增加 default-autowire 屬性,設置默認的自動封裝策略。默認值為"no"。如果使用自動裝配的同時,也指定了 property 或者 constructor-arg 標簽,則顯式指定的值將覆蓋自動裝配的值。目前的自動封裝不支持簡單類型,比如基本類型、String、Class,以及它們的數組類型。

在按類型匹配的時候 ( 可能是 byType、constructor、autodetect),同一個類型可能存在多個 Bean,如果被注入的屬性是數組、集合或者 Map,這可能沒有問題,但是如果只是簡單的引用類型,則會拋出異常。解決方法有如下幾種:

♦ 取消該 Bean 的自動裝配特性,使用顯式的注入。我們可能不希望某個 Bean 被當作其他 Bean 執(zhí)行自動封裝時的候選對象,我們可以給該 增加 autowire-candidate="false"。(autowire-candidate 屬性和 autowire 屬性相互獨立,互不相干。某個 Bean 可以將 autowire-candidate 設置為 false,同時使用 autowire 特性。) 另外,我們可以設置 的 default-autowire-candidates 屬性,可以在該屬性中指定可以用于自動裝配候選 Bean 的匹配模式,比如 default-autowire-candidates="*serv,*dao",這表示所有名字以 serv 或者 dao 結尾的 Bean 被列為候選,其他則忽略,相當于其他 Bean 都指定為 autowire-candidate="false",此時可以顯式為 指定 autowire-candidate="true"。在 上指定的設置要覆蓋 上指定的設置。

♦ 如果在多個類型相同的 Bean 中有首選的 Bean,那么可以將該 的 primary 屬性設置為 "true" ,這樣自動裝配時便優(yōu)先使用該 Bean 進行裝配。此時不能將 autowire-candidate 設為 false。

♦ 如果使用的是 Java 5 以上版本,可以使用注解進行更細粒度的控制。

使用 @Autowired 和 @Qualifier 注解執(zhí)行自動裝配

使用 @Autowired 注解進行裝配,只能是根據類型進行匹配。@Autowired 注解可以用于 Setter 方法、構造函數、字段,甚至普通方法,前提是方法必須有至少一個參數。@Autowired 可以用于數組和使用泛型的集合類型。然后 Spring 會將容器中所有類型符合的 Bean 注入進來。@Autowired 標注作用于 Map 類型時,如果 Map 的 key 為 String 類型,則 Spring 會將容器中所有類型符合 Map 的 value 對應的類型的 Bean 增加進來,用 Bean 的 id 或 name 作為 Map 的 key。

@Autowired 標注作用于普通方法時,會產生一個副作用,就是在容器初始化該 Bean 實例的時候就會調用該方法。當然,前提是執(zhí)行了自動裝配,對于不滿足裝配條件的情況,該方法也不會被執(zhí)行。

當標注了 @Autowired 后,自動注入不能滿足,則會拋出異常。我們可以給 @Autowired 標注增加一個 required=false 屬性,以改變這個行為。另外,每一個類中只能有一個構造函數的 @Autowired.required() 屬性為 true。否則就出問題了。如果用 @Autowired 同時標注了多個構造函數,那么,Spring 將采用貪心算法匹配構造函數 ( 構造函數最長 )。

@Autowired 還有一個作用就是,如果將其標注在 BeanFactory 類型、ApplicationContext 類型、ResourceLoader 類型、ApplicationEventPublisher 類型、MessageSource 類型上,那么 Spring 會自動注入這些實現類的實例,不需要額外的操作。

當容器中存在多個 Bean 的類型與需要注入的相同時,注入將不能執(zhí)行,我們可以給 @Autowired 增加一個候選值,做法是在 @Autowired 后面增加一個 @Qualifier 標注,提供一個 String 類型的值作為候選的 Bean 的名字。舉例如下:

  1. @Autowired(required=false)   
  2. @Qualifier("ppp")   
  3. public void setPerson(person p){}   

@Qualifier 甚至可以作用于方法的參數 ( 對于方法只有一個參數的情況,我們可以將 @Qualifer 標注放置在方法聲明上面,但是推薦放置在參數前面 ),舉例如下:

  1. @Autowired(required=false)   
  2. public void sayHello(@Qualifier("ppp")Person p,String name){}  

我們可以在配置文件中指定某個 Bean 的 qualifier 名字,方法如下:

  1. <bean id="person" class="footmark.spring.Person">   
  2.     <qualifier value="ppp"/>   
  3. bean>  

如果沒有明確指定 Bean 的 qualifier 名字,那么默認名字就是 Bean 的名字。通常,qualifier 應該是有業(yè)務含義的,例如 "domain","persistent" 等,而不應該是類似 "person" 方式。

我們還可以將 @Qualifier 標注在集合類型上,那么所有 qualifier 名字與指定值相同的 Bean 都將被注入進來。

最后,配置文件中需要指定每一個自定義注解的屬性值。我們可以使用 標簽來代替 標簽,如果 標簽和 標簽同時出現,那么優(yōu)先使用 標簽。如果沒有 標簽,那么會用 提供的鍵值對來封裝 標簽。示例如下:

  1. <bean class="footmark.HelloWorld">   
  2. <qualifier type="MovieQualifier">   
  3. <attribute key="format" value="VHS"/>   
  4. <attribute key="genre" value="Comedy"/>   
  5. qualifier>   
  6. bean>   
  7. <bean class="footmark.HelloWorld">   
  8. <meta key="format" value="DVD"/>   
  9. <meta key="genre" value="Action"/>   
  10. bean>   

@Autowired 注解對應的后處理注冊與前面相似,只需在配置文件中增加如下一行即可:

  1. <context:annotation-config/>   

如果 @Autowired 注入的是 BeanFactory、ApplicationContext、ResourceLoader 等系統(tǒng)類型,那么則不需要 @Qualifier,此時即使提供了 @Qualifier 注解,也將會被忽略;而對于自定義類型的自動裝配,如果使用了 @Qualifier 注解并且沒有名字與之匹配的 Bean,則自動裝配匹配失敗。

#p#

使用 JSR-250 中的 @Resource 和 @Qualifier 注解

如果希望根據 name 執(zhí)行自動裝配,那么應該使用 JSR-250 提供的 @Resource 注解,而不應該使用 @Autowired 與 @Qualifier 的組合。

@Resource 使用 byName 的方式執(zhí)行自動封裝。@Resource 標注可以作用于帶一個參數的 Setter 方法、字段,以及帶一個參數的普通方法上。@Resource 注解有一個 name 屬性,用于指定 Bean 在配置文件中對應的名字。如果沒有指定 name 屬性,那么默認值就是字段或者屬性的名字。@Resource 和 @Qualifier 的配合雖然仍然成立,但是 @Qualifier 對于 @Resource 而言,幾乎與 name 屬性等效。

如果 @Resource 沒有指定 name 屬性,那么使用 byName 匹配失敗后,會退而使用 byType 繼續(xù)匹配,如果再失敗,則拋出異常。在沒有為 @Resource 注解顯式指定 name 屬性的前提下,如果將其標注在 BeanFactory 類型、ApplicationContext 類型、ResourceLoader 類型、ApplicationEventPublisher 類型、MessageSource 類型上,那么 Spring 會自動注入這些實現類的實例,不需要額外的操作。此時 name 屬性不需要指定 ( 或者指定為""),否則注入失敗;如果使用了 @Qualifier,則該注解將被忽略。而對于用戶自定義類型的注入,@Qualifier 和 name 等價,并且不被忽略。

的 primary 和 autowire-candidate 屬性對 @Resource、@Autowired 仍然有效。

使用 @Configuration 和 @Bean 進行 Bean 的聲明

雖然 2.0 版本發(fā)布以來,Spring 陸續(xù)提供了十多個注解,但是提供的這些注解只是為了在某些情況下簡化 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 容器的唯一配置方式。兩者在一定范圍內存在著競爭的關系,但是它們在大多數情況下還是相互協(xié)作的關系,兩者的結合使得 Spring IoC 容器的配置更簡單,更強大。

之前,我們將配置信息集中寫在 XML 中,如今使用注解,配置信息的載體由 XML 文件轉移到了 Java 類中。我們通常將用于存放配置信息的類的類名以 “Config” 結尾,比如 AppDaoConfig.java、AppServiceConfig.java 等等。我們需要在用于指定配置信息的類上加上 @Configuration 注解,以明確指出該類是 Bean 配置的信息源。并且 Spring 對標注 Configuration 的類有如下要求:

♦ 配置類不能是 final 的;

♦ 配置類不能是本地化的,亦即不能將配置類定義在其他類的方法內部;

♦ 配置類必須有一個無參構造函數。

AnnotationConfigApplicationContext 將配置類中標注了 @Bean 的方法的返回值識別為 Spring Bean,并注冊到容器中,受 IoC 容器管理。@Bean 的作用等價于 XML 配置中的 標簽。示例如下:

  1. @Configuration   
  2. public class BookStoreDaoConfig{   
  3.     @Bean   
  4.     public UserDao userDao(){ return new UserDaoImpl();}   
  5.     @Bean   
  6.     public BookDao bookDao(){return new BookDaoImpl();}   
  7. }   

Spring 在解析到以上文件時,將識別出標注 @Bean 的所有方法,執(zhí)行之,并將方法的返回值 ( 這里是 UserDaoImpl 和 BookDaoImpl 對象 ) 注冊到 IoC 容器中。默認情況下,Bean 的名字即為方法名。因此,與以上配置等價的 XML 配置如下:

  1. <bean id=”userDao” class=”bookstore.dao.UserDaoImpl”/>    
  2.  <bean id=”bookDao” class=”bookstore.dao.BookDaoImpl”/>       

    

@Bean 具有以下四個屬性:

♦ name -- 指定一個或者多個 Bean 的名字。這等價于 XML 配置中 的 name 屬性。

♦ initMethod -- 容器在初始化完 Bean 之后,會調用該屬性指定的方法。這等價于 XML 配置中 的 init-method 屬性。

♦ destroyMethod -- 該屬性與 initMethod 功能相似,在容器銷毀 Bean 之前,會調用該屬性指定的方法。這等價于 XML 配置中 的 destroy-method 屬性。

♦ autowire -- 指定 Bean 屬性的自動裝配策略,取值是 Autowire 類型的三個靜態(tài)屬性。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() 方法,其功能與上面也類似,該方法主要用在容器初始化之后動態(tài)增加 Bean 至容器中。調用了該方法以后,通常需要立即手動調用 refresh() 刷新容器,以讓變更立即生效。

需要注意的是,AnnotationConfigApplicationContext 在解析配置類時,會將配置類自身注冊為一個 Bean,因為 @Configuration 注解本身定義時被 @Component 標注了。因此可以說,一個 @Configuration 同時也是一個 @Component。大多數情況下,開發(fā)者用不到該 Bean,并且在理想情況下,該 Bean 應該是對開發(fā)者透明的。@Configuration 的定義如下所示:

  1. @Target({ElementType.TYPE})   
  2. @Retention(RetentionPolicy.RUNTIME)   
  3. @Documented   
  4. @Component   
  5. public @interface Configuration {   
  6. String value() default "";   
  7. }   

在一般的項目中,為了結構清晰,通常會根據軟件的模塊或者結構定義多個 XML 配置文件,然后再定義一個入口的配置文件,該文件使用 將其他的配置文件組織起來。最后只需將該文件傳給 ClassPathXmlApplicationContext 的構造函數即可。針對基于注解的配置,Spring 也提供了類似的功能,只需定義一個入口配置類,并在該類上使用 @Import 注解引入其他的配置類即可,最后只需要將該入口類傳遞給 AnnotationConfigApplicationContext。具體示例如下:

  1. @Configuration   
  2. @Import({BookStoreServiceConfig.class,BookStoreDaoConfig.class})   
  3. public class BookStoreConfig{ … }  

混合使用 XML 與注解進行 Bean 的配置

設計 @Configuration 和 @Bean 的初衷,并不是為了完全取代 XML,而是為了在 XML 之外多一種可行的選擇。由于 Spring 自發(fā)布以來,Spring 開發(fā)小組便不斷簡化 XML 配置,使得 XML 配置方式已經非常成熟,加上 Spring 2.0 以后出現了一系列命名空間的支持,使得 XML 配置方式成為了使用簡單、功能強大的 Bean 定義方式。而且,XML 配置的一些高級功能目前還沒有相關注解能夠直接支持。因此,在目前的多數項目中,要么使用純粹的 XML 配置方式進行 Bean 的配置,要么使用以注解為主,XML 為輔的配置方式進行 Bean 的配置。

之所以會出現兩者共存的情況,主要歸結為三個原因:其一,目前絕大多數采用 Spring 進行開發(fā)的項目,幾乎都是基于 XML 配置方式的,Spring 在引入注解的同時,必須保證注解能夠與 XML 和諧共存,這是前提;其二,由于注解引入較晚,因此功能也沒有發(fā)展多年的 XML 強大,因此,對于復雜的配置,注解還很難獨當一面,在一段時間內仍然需要 XML 的配合才能解決問題。除此之外,Spring 的 Bean 的配置方式與 Spring 核心模塊之間是解耦的,因此,改變配置方式對 Spring 的框架自身是透明的。Spring 可以通過使用 Bean 后處理器 (BeanPostProcessor) 非常方便的增加對于注解的支持。這在技術實現上非常容易的事情。

要使用混合配置方式,首先需要判斷以哪一種配置方式為主。對這個問題的不同回答將會直接影響到實現的方式。然而大可不必為此傷腦筋,因為不論是以 XML 為主,還是以注解為主,配置方式都是簡單而且容易理解的。這里不存在錯誤的決定,因為僅僅是表現方式不一樣。我們首先假設以 XML 配置為主的情況。

對于已經存在的大型項目,可能初期是以 XML 進行 Bean 配置的,后續(xù)逐漸加入了注解的支持,這時我們只需在 XML 配置文件中將被 @Configuration 標注的類定義為普通的 ,同時注冊處理注解的 Bean 后處理器即可。示例如下:

// 假設存在如下的 @Configuration 類:

  1. package bookstore.config;   
  2. import bookstore.dao.*;   
  3. @Configuration   
  4. public class MyConfig{   
  5. @Bean   
  6.     public UserDao userDao(){   
  7.         return new UserDaoImpl();   
  8.     }   
  9. }  

此時,只需在 XML 中作如下聲明即可:

  1. <beans … >   
  2.     ……   
  3.     <context:annotation-config />   
  4.     <bean class=”demo.config.MyConfig”/>   
  5. beans>  

由于啟用了針對注解的 Bean 后處理器,因此在 ApplicationContext 解析到 MyConfig 類時,會發(fā)現該類標注了 @Configuration 注解,隨后便會處理該類中標注 @Bean 的方法,將這些方法的返回值注冊為容器總的 Bean。

對于以上的方式,如果存在多個標注了 @Configuration 的類,則需要在 XML 文件中逐一列出。另一種方式是使用前面提到的自動掃描功能,配置如下:

  1. <context:component-scan base-package=”bookstore.config” />  

如此,Spring 將掃描所有 demo.config 包及其子包中的類,識別所有標記了 @Component、@Controller、@Service、@Repository 注解的類,由于 @Configuration 注解本身也用 @Component 標注了,Spring 將能夠識別出 @Configuration 標注類并正確解析之。

對于以注解為中心的配置方式,只需使用 @ImportResource 注解引入存在的 XML 即可,如下所示:

  1. @Configuration   
  2. @ImportResource(“classpath:/bookstore/config/spring-beans.xml”)   
  3. public class MyConfig{   
  4. ……   
  5. }   

// 容器的初始化過程和純粹的以配置為中心的方式一致:

  1. AnnotationConfigApplicationContext ctx =   
  2.               new AnnotationConfigApplicationContext(MyConfig.class);   
  3. ……  

結束語

從 2.0 版本開始,Spring 的每一次更新都會提供更多新的注解供開發(fā)者使用。這滿足了注解愛好者的胃口。但是正如前面所說,Spring 提供更多的注解并不是為了有朝一日取代 XML 配置方式,而是為了給開發(fā)者多一種選擇。兩種聲明 Bean 的方式各有特色,XML 方式更加靈活,并且發(fā)展的相對成熟,這種配置方式為大多數 Spring 開發(fā)者熟悉;注解方式使用起來非常簡潔,但是尚處于發(fā)展階段。我們很難說兩種配置方式孰優(yōu)孰劣,但是如果能夠靈活搭配兩種方式,一定能夠進一步提升開發(fā)效率。



【編輯推薦】

  1. Java EE進階之Spring事務深入淺出
  2. Spring事務管理高級應用難點剖析
  3. Spring-MVC入門(一):入門實例
  4. 多圖詳解Spring框架的設計理念與設計模式
責任編輯:金賀 來源: JavaEye博客
相關推薦

2011-05-31 10:00:21

Android Spring 依賴注入

2015-09-02 11:22:36

JavaScript實現思路

2017-08-16 16:00:05

PHPcontainer依賴注入

2022-04-30 08:50:11

控制反轉Spring依賴注入

2016-03-21 17:08:54

Java Spring注解區(qū)別

2011-04-15 09:44:45

Spring

2024-11-27 00:24:04

2020-08-06 00:14:16

Spring IoC依賴注入開發(fā)

2009-09-08 15:22:20

Spring依賴注入

2010-10-14 09:05:36

ASP.NET MVC

2022-12-29 08:54:53

依賴注入JavaScript

2023-10-07 08:35:07

依賴注入Spring

2020-02-10 15:50:18

Spring循環(huán)依賴Java

2025-02-17 00:00:55

NET開發(fā)依賴注入

2018-03-12 10:02:30

PHP依賴注入

2012-07-22 20:34:27

springMVCJUnit

2020-11-02 07:00:29

Spring Boo注解自動化

2021-07-29 06:55:03

Spring@AutowriedbyType注入

2024-08-27 11:00:56

單例池緩存bean

2024-08-26 08:52:41

點贊
收藏

51CTO技術棧公眾號

亚洲国产精品av| 国产欧美精品| 亚洲成人网久久久| jizzjizz国产精品喷水| 超碰在线影院| 国产传媒日韩欧美成人| 91高清视频免费观看| 精品一区二区三区蜜桃在线| 欧美成人精品午夜一区二区| 欧美性猛交xxxx乱大交极品| 在线观看日韩片| 完全免费av在线播放| 久久精品人人| 欧美裸体xxxx极品少妇| 国产成人精品无码免费看夜聊软件| 国产麻豆一区| 精品日韩视频在线观看| 国产欧美综合一区| 69av亚洲| 91浏览器在线视频| 91久久久久久国产精品| 无码人妻熟妇av又粗又大| 欧美三级网页| 日韩有码在线观看| 一区二区三区久久久久| 国产精品极品在线观看| 91精品国产综合久久香蕉的特点 | 久久久久久久久影院| 91成人影院| 在线观看欧美日韩| 国产精品无码网站| 成人中文字幕视频| 日韩西西人体444www| 少妇一级淫免费放| **在线精品| 亚洲成av人片在线| 欧美精品在欧美一区二区| 成人高清免费在线播放| 久久免费视频色| 古典武侠综合av第一页| 国产视频手机在线观看| 久久99热国产| 91精品国产自产在线观看永久| 免费污污视频在线观看| 国产亚洲欧洲| 青青草国产精品一区二区| 日韩视频免费观看高清| 亚洲免费高清| 欧美资源在线观看| 久久亚洲天堂网| 午夜亚洲性色福利视频| 欧美性一区二区三区| 日韩三级av在线| 日韩一区二区久久| 97av在线播放| 手机看片久久久| 日韩精品午夜视频| 国产精品一区二区三区毛片淫片| 欧美日韩a v| 日本欧美一区二区三区| 国产精品激情自拍| 在线观看免费观看在线| 久草热8精品视频在线观看| 国产在线视频一区| 国产情侣在线播放| 成人自拍视频在线| 久热这里只精品99re8久 | 91尤物国产福利在线观看| 久久精品国产999大香线蕉| 国产在线高清精品| 精品人妻aV中文字幕乱码色欲| 粉嫩av一区二区三区在线播放 | 亚洲va韩国va欧美va| 欧美爱爱视频免费看| 日日夜夜天天综合| 在线成人av影院| 中文字幕乱妇无码av在线| 都市激情亚洲| 亚洲天堂av在线播放| 长河落日免费高清观看| 在线看片不卡| 69精品小视频| 一本色道久久综合精品婷婷| 国产精品资源在线| 精品欧美日韩| 日韩大片在线永久免费观看网站| 亚洲精品久久久蜜桃| 国产日韩亚洲欧美在线| 小早川怜子影音先锋在线观看| 日本久久精品电影| 黑人巨大猛交丰满少妇| 日韩av影院| 菠萝蜜影院一区二区免费| 国产一级做a爰片在线看免费| 麻豆精品91| 91欧美视频网站| 日色在线视频| 亚洲狼人国产精品| 成人中文字幕在线播放| 97精品资源在线观看| 日韩av在线看| 极品久久久久久| 久久久久国产一区二区| 97超碰资源| 福利视频在线播放| 性久久久久久久久| 亚洲精品在线视频播放| 亚洲春色h网| 欧美激情在线有限公司| 亚洲永久精品视频| 99re8在线精品视频免费播放| 一区二区视频在线免费| 电影网一区二区| 欧美videos大乳护士334| 亚洲一级黄色录像| 国产日韩亚洲| 国产精品日韩高清| 老司机精品视频在线观看6| 色欧美日韩亚洲| 手机免费看av片| 亚洲精品中文字幕乱码| 国产精品视频免费观看www| 天堂在线视频免费| 亚洲五码中文字幕| 日韩av影视大全| 久久一区二区三区喷水| 日韩av大片免费看| 日韩一区av| 五月激情六月综合| 最新中文字幕日本| 欧美一区91| 91久久久久久久久| av在线三区| 日本电影亚洲天堂一区| 野外性满足hd| 国产模特精品视频久久久久| 极品尤物一区二区三区| 黄色羞羞视频在线观看| 欧美电影免费提供在线观看| caoporn91| 国产一区二区女| 亚洲精品偷拍视频| 动漫一区二区三区| 久热在线中文字幕色999舞| 国产一区二区自拍视频| 国产精品福利在线播放| 中文字幕视频三区| 99视频精品全部免费在线视频| 国产精品免费网站| 日本高清中文字幕在线| 欧美巨大另类极品videosbest| 日本一卡二卡在线播放| 美女视频黄免费的久久| 伊人色综合久久天天五月婷| 欧美电影在线观看网站| 久久在线观看视频| 国产黄色av网站| 亚洲高清免费观看高清完整版在线观看 | 美女一区二区视频| 在线成人av电影| 国产精品18| 欧美激情手机在线视频| 成人免费视频国产| 欧美日韩一区二区免费视频| 欧美特级黄色录像| 久久国产精品区| 奇米777四色影视在线看| 大香伊人久久精品一区二区| 88国产精品欧美一区二区三区| 精华区一区二区三区| 欧美午夜一区二区三区| 日本中文字幕免费在线观看| 成人夜色视频网站在线观看| 无码人妻h动漫| 91偷拍一区二区三区精品| 91中文字幕在线| 国产精品一二三产区| 国产午夜精品视频| 99国产精品99| 精品欧美aⅴ在线网站| 亚洲午夜久久久久久久国产| 国产麻豆成人精品| 精品人妻一区二区三区四区在线| 欧美丝袜激情| 国产福利一区二区三区在线观看| 少妇视频在线观看| 久久久成人av| 三级av在线播放| 欧美一区二区三区免费在线看| 日韩特黄一级片| 国产精品久久777777| 亚洲精品无码一区二区| 日韩福利视频网| 日韩免费在线观看av| 狠狠色丁香婷婷综合影院| 亚洲综合自拍一区| 成人看片网页| 久久久久久久成人| 日韩伦理在线观看| 亚洲乱亚洲乱妇无码| 国产高清免费av| 在线观看视频一区二区欧美日韩| 青青草手机在线视频| 欧美国产一区在线| 亚洲av无码一区二区三区网址 | 91精品国产高清久久久久久91裸体| 夜鲁夜鲁夜鲁视频在线播放| 久久精品视频在线| 黄色电影免费在线看| 亚洲精品一区二区三区福利| 在线观看免费黄色小视频| 欧美午夜宅男影院在线观看| 欧美激情图片小说| 中文字幕中文在线不卡住| 毛片网站免费观看| 成+人+亚洲+综合天堂| 日本在线观看视频一区| 强制捆绑调教一区二区| 日本精品一区在线观看| 午夜日韩在线| 亚洲日本无吗高清不卡| 欧美精品乱码| 欧美日韩最好看的视频| 秋霞在线一区| 国产伦精品一区二区三区视频免费| 亚洲人成网站在线在线观看| 国产精品免费一区豆花| 忘忧草在线www成人影院| 国产69久久精品成人| 国产精品一二三产区| 午夜精品三级视频福利| 波多野结依一区| 色综合久久天天综线观看| a级网站在线播放| 日韩日本欧美亚洲| 77导航福利在线| 日韩三级影视基地| 久cao在线| 久久夜色撩人精品| gogo在线观看| 欧美成人免费在线视频| 永久免费网站在线| 欧美老少配视频| 色呦呦在线观看视频| 久久99久久99精品免观看粉嫩| 国产欧美久久久久久久久| 久久这里只有精品99| 在线欧美三级| 久久免费少妇高潮久久精品99| 超碰在线最新网址| 97视频免费在线观看| 欧美日韩国产观看视频| 日本最新高清不卡中文字幕| 欧美天堂视频| 国产日本欧美在线观看| 警花av一区二区三区| 99久热re在线精品视频| 久久悠悠精品综合网| 就去色蜜桃综合| 国内精品久久久久久久久电影网| 亚洲一区二区三区乱码| 欧美精品导航| 97国产在线播放| 日韩av不卡一区二区| 国产女同无遮挡互慰高潮91| 国产精品夜夜爽| 国产精品久久不卡| 亚洲国产精品99久久久久久久久| 麻豆网址在线观看| 亚洲成人第一页| 欧美黄色一级大片| 在线综合+亚洲+欧美中文字幕| 亚洲精选一区二区三区| 国产婷婷色综合av蜜臀av | **性色生活片久久毛片| 2021亚洲天堂| 日韩欧美中文字幕在线播放| 在线观看亚洲国产| 亚洲成人激情图| 成年午夜在线| 色综合久久悠悠| 美女100%一区| 999视频在线免费观看| 日韩精品免费一区二区三区竹菊| 亚洲欧美日韩国产yyy| 欧美日韩福利| 91人人澡人人爽人人精品| 国产白丝网站精品污在线入口| 蜜桃精品一区二区| 亚洲欧美日韩精品久久久久| 国产黄色片免费看| 欧美肥胖老妇做爰| 水莓100在线视频| 久久视频在线免费观看| 久久uomeier| 97视频中文字幕| 欧美亚洲激情| 男人添女荫道口图片| 久久99深爱久久99精品| 亚洲最大成人网站| 一区二区三区免费看视频| 波多野结衣一区二区三区四区| 日韩美一区二区三区| av在线播放av| 日本aⅴ大伊香蕉精品视频| 日韩在线观看一区二区三区| 热re99久久精品国99热蜜月| 国产一区二区三区四区老人| 国产精品视频中文字幕| 久久久欧美精品sm网站| 国产精品第九页| 日韩欧美区一区二| 思思99re6国产在线播放| 欧美亚洲另类激情另类| 亚洲精品黑牛一区二区三区| 亚洲欧美日韩国产yyy| 日日夜夜一区二区| 美女又爽又黄视频毛茸茸| 亚洲免费观看视频| 一区二区三区精彩视频| 亚洲一区www| 国产精品亚洲一区二区三区在线观看| 国产九色91| 欧美天天在线| 超碰在线超碰在线| 亚洲天堂成人网| 亚洲无码精品在线播放| 色系列之999| 伦一区二区三区中文字幕v亚洲| 欧美精品七区| 鲁大师成人一区二区三区| av直播在线观看| 欧美日韩国产精品一区| 人人妻人人澡人人爽久久av| 欧美激情一级二级| xxxx日韩| 丁香花在线影院观看在线播放| 成人免费毛片aaaaa**| 久操视频免费在线观看| 精品欧美黑人一区二区三区| 手机av在线播放| 亚洲视频小说图片| 91精品国产乱码久久久张津瑜| 精品人伦一区二区色婷婷| 日本乱理伦在线| 国产精品对白一区二区三区| 国产精品草草| 秘密基地免费观看完整版中文 | 91看片淫黄大片91| 国产黄色91视频| 精品无码久久久久久久| 精品国产99国产精品| segui88久久综合9999| 精品免费视频123区| 久久天天综合| 超碰人人人人人人人| 欧美片在线播放| 四虎亚洲成人| 国产日韩欧美亚洲一区| 亚洲视频播放| 激情五月深爱五月| 欧美一级淫片007| 国产蜜臀在线| 欧美久久久久久久| 久久99国产精品久久99果冻传媒| 永久av免费网站| 精品国产乱码久久久久久牛牛| 国产美女高潮在线| 亚洲不卡1区| 蜜桃久久av一区| 国产亚洲精品成人| 亚洲精品自产拍| 四虎影视国产精品| 激情五月婷婷六月| 久久久午夜电影| 国产伦精品一区二区三区视频痴汉| 九九热这里只有精品6| 色天下一区二区三区| 中文字幕精品一区二区三区在线| 亚洲一区在线观看免费观看电影高清 | 五月婷婷综合色| 国产成人综合视频| 精品国产午夜福利| 久久国产精品久久久久| 天堂成人娱乐在线视频免费播放网站 | 欧美三级黄色大片| 亚洲黄色在线看| 日韩欧美专区| 91视频最新入口| 亚洲女人的天堂| 毛片网站在线| 99电影在线观看| 日本vs亚洲vs韩国一区三区| 欧美日韩精品亚洲精品| 亚洲色图美腿丝袜| 136福利精品导航| 中文字幕av不卡在线| 午夜精品一区二区三区免费视频| 亚洲图片88| 麻豆久久久9性大片|