spring使用註解注入bean理解

shadow_zed發表於2017-05-19

                    註解實現Bean依賴注入

 1.概述

       註解實現Bean配置主要用來進行如依賴注入、生命週期回撥方法定義等,不能消除XML檔案中的Bean後設資料定義,且基於XML配置中的依賴注入的資料將覆蓋基於註解配置中的依賴注入的資料

 

Spring3的基於註解實現Bean依賴注入支援如下三種註解:

  • Spring自帶依賴注入註解: Spring自帶的一套依賴注入註解;
  • JSR-250註解:Java平臺的公共註解,是Java EE 5規範之一,在JDK6中預設包含這些註解,從Spring2.5開始支援。
  • JSR-330註解:Java 依賴注入標準,Java EE 6規範之一,可能在加入到未來JDK版本,從Spring3開始支援;
  • JPA註解:用於注入持久化上下文和屍體管理器。

 

這三種型別的註解在Spring3中都支援,類似於註解事務支援,想要使用這些註解需要在Spring容器中開啟註解驅動支援,即使用如下配置方式開啟:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <beans xmlns="http://www.springframework.org/schema/beans"  
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.     xmlns:context="http://www.springframework.org/schema/context"  
  4.     xsi:schemaLocation=" http://www.springframework.org/schema/beans  
  5.        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  6.        http://www.springframework.org/schema/context  
  7.        http://www.springframework.org/schema/context/spring-context-3.0.xsd">  
  8.   
  9.     <context:annotation-config/>  
  10.   
  11. </beans>  
  12.    
  13.    

   這樣就能使用註解驅動依賴注入了,該配置檔案位於“resources/ chapter12/dependecyInjectWithAnnotation.xml”。

 

2.  Spring自帶依賴注入註解

一、@Required:依賴檢查;

對應於基於XML配置中的依賴檢查,但XML配置的依賴檢查將檢查所有setter方法,詳見【3.3.4  依賴檢查】;

基於@Required的依賴檢查表示註解的setter方法必須,即必須通過在XML配置中配置setter注入,如果沒有配置在容器啟動時會丟擲異常從而保證在執行時不會遇到空指標異常,@Required只能放置在setter方法上,且通過XML配置的setter注入,可以使用如下方式來指定:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Requried  
  2. setter方法  

 

1、準備測試Bean

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. public class TestBean {  
  3.     private String message;  
  4.     @Required  
  5.     public void setMessage(String message) {  
  6.         this.message = message;  
  7.     }  
  8.     public String getMessage() {  
  9.         return message;  
  10.     }  
  11. }  

 

 

2、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="testBean" class="cn.javass.spring.chapter12.TestBean">  
  2. <property name="message" ref="message"/>  
  3. </bean>  
  4. <bean id="message" class="java.lang.String">  
  5.     <constructor-arg index="0" value="hello"/>  
  6. </bean>  

 

3、測試類和測試方法如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. //省略import  
  3. public class DependencyInjectWithAnnotationTest {  
  4.     private static String configLocation = "classpath:chapter12/dependecyInjectWithAnnotation.xml";  
  5.     private static ApplicationContext ctx = new ClassPathXmlApplicationContext("configLocation");  
  6.     //1、Spring自帶依賴注入註解  
  7.      @Test  
  8.     public void testRequiredForXmlSetterInject() {  
  9.         TestBean testBean = ctx.getBean("testBean", TestBean.class);  
  10.         Assert.assertEquals("hello", testBean.getMessage());  
  11.     }  
  12. }  

 

在XML配置檔案中必須指定setter注入,否則在Spring容器啟動時將丟擲如下異常:

 

java程式碼:
Java程式碼  收藏程式碼
  1. org.springframework.beans.factory.BeanCreationException:  
  2. Error creating bean with name 'testBean' defined in class path resource [chapter12/dependecyInjectWithAnnotation.xml]: Initialization of bean failed;  
  3. nested exception is org.springframework.beans.factory.BeanInitializationException: Property 'message' is required for bean 'testBean'  

 

 

 

 

二、@Autowired:自動裝配

自動裝配,用於替代基於XML配置的自動裝配,詳見【3.3.3  自動裝配】。

 

基於@Autowired的自動裝配,預設是根據型別注入,可以用於構造器、欄位、方法注入,使用方式如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Autowired(required=true)  
  2. 構造器、欄位、方法  

 

@Autowired預設是根據引數型別進行自動裝配,且必須有一個Bean候選者注入,如果允許出現0個Bean候選者需要設定屬性“required=false”,“required”屬性含義和@Required一樣,只是@Required只適用於基於XML配置的setter注入方式。

 

(1)、構造器注入:通過將@Autowired註解放在構造器上來完成構造器注入,預設構造器引數通過型別自動裝配,如下所示:

 

1、準備測試Bean,在構造器上新增@AutoWired註解:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. import org.springframework.beans.factory.annotation.Autowired;  
  3. public class TestBean11 {  
  4.     private String message;  
  5.     @Autowired //構造器注入  
  6.     private TestBean11(String message) {  
  7.         this.message = message;  
  8.     }  
  9.     //省略message的getter和setter  
  10. }  

 

 

2、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="testBean11" class="cn.javass.spring.chapter12.TestBean11"/>  

 

3、測試類如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void testAutowiredForConstructor() {  
  3.     TestBean11 testBean11 = ctx.getBean("testBean11", TestBean11.class);  
  4.     Assert.assertEquals("hello", testBean11.getMessage());  
  5. }  

    在Spring配置檔案中沒有對“testBean11”進行構造器注入和setter注入配置,而是通過在構造器上新增@ Autowired來完成根據引數型別完成構造器注入。

 

 

 

(2)、欄位注入:通過將@Autowired註解放在構造器上來完成欄位注入。

 

1、準備測試Bean,在欄位上新增@AutoWired註解:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. import org.springframework.beans.factory.annotation.Autowired;  
  3. public class TestBean12 {  
  4.     @Autowired //欄位注入  
  5.     private String message;  
  6.     //省略getter和setter  
  7. }  

 

 

2、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="testBean12" class="cn.javass.spring.chapter12.TestBean12"/>  

 

3、測試方法如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void testAutowiredForField() {  
  3.     TestBean12 testBean12 = ctx.getBean("testBean12", TestBean12.class);  
  4.     Assert.assertEquals("hello", testBean12.getMessage());  
  5. }  

    欄位注入在基於XML配置中無相應概念,欄位注入不支援靜態型別欄位的注入。

 

 

(3)、方法引數注入:通過將@Autowired註解放在方法上來完成方法引數注入。

 

1、準備測試Bean,在方法上新增@AutoWired註解:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. import org.springframework.beans.factory.annotation.Autowired;  
  3. public class TestBean13 {  
  4.     private String message;  
  5.     @Autowired //setter方法注入  
  6.     public void setMessage(String message) {  
  7.         this.message = message;  
  8.     }  
  9.     public String getMessage() {  
  10.         return message;  
  11.     }  
  12. }  

 

 

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. //省略import  
  3. public class TestBean14 {  
  4.     private String message;  
  5.     private List<String> list;  
  6.     @Autowired(required = true//任意一個或多個引數方法注入  
  7.     private void initMessage(String message, ArrayList<String> list) {  
  8.         this.message = message;  
  9.         this.list = list;  
  10.     }  
  11.     //省略getter和setter  
  12. }  

 

2、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="testBean13" class="cn.javass.spring.chapter12.TestBean13"/>  
  2. <bean id="testBean14" class="cn.javass.spring.chapter12.TestBean14"/>  
  3. <bean id="list" class="java.util.ArrayList">  
  4.     <constructor-arg index="0">  
  5.         <list>  
  6.             <ref bean="message"/>  
  7.             <ref bean="message"/>  
  8.         </list>  
  9.    </constructor-arg>          
  10. </bean>  

 

3、測試方法如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void testAutowiredForMethod() {  
  3.     TestBean13 testBean13 = ctx.getBean("testBean13", TestBean13.class);  
  4.     Assert.assertEquals("hello", testBean13.getMessage());  
  5.    
  6.     TestBean14 testBean14 = ctx.getBean("testBean14", TestBean14.class);  
  7.     Assert.assertEquals("hello", testBean14.getMessage());  
  8.     Assert.assertEquals(ctx.getBean("list", List.class), testBean14.getList());  
  9. }  
  10.    

 

方法引數注入除了支援setter方法注入,還支援1個或多個引數的普通方法注入,在基於XML配置中不支援1個或多個引數的普通方法注入,方法注入不支援靜態型別方法的注入。

 

注意“initMessage(String message, ArrayList<String> list)”方法簽名中為什麼使用ArrayList而不是List呢?具體參考【3.3.3  自動裝配】一節中的集合型別注入區別。

 

 

 

 

 

三、@Value:注入SpEL表示式;

 

用於注入SpEL表示式,可以放置在欄位方法或引數上,使用方式如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Value(value = "SpEL表示式")  
  2. 欄位、方法、引數  

 

1、可以在類欄位上使用該註解:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Value(value = "#{message}")  
  2. private String message;  

 

2、可以放置在帶@Autowired註解的方法的引數上:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Autowired  
  2. public void initMessage(@Value(value = "#{message}#{message}") String message) {  
  3.     this.message = message;  
  4. }  

 

3、還可以放置在帶@Autowired註解的構造器的引數上:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Autowired  
  2. private TestBean43(@Value(value = "#{message}#{message}") String message) {  
  3.     this.message = message;  
  4. }  

    具體測試詳見DependencyInjectWithAnnotationTest 類的testValueInject測試方法。

 

 

 

 

四、@Qualifier:限定描述符,用於細粒度選擇候選者;

 

@Autowired預設是根據型別進行注入的,因此如果有多個型別一樣的Bean候選者,則需要限定其中一個候選者,否則將丟擲異常,詳見【3.3.3  自動裝配】中的根據型別進行注入;

 

@Qualifier限定描述符除了能根據名字進行注入,但能進行更細粒度的控制如何選擇候選者,具體使用方式如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Qualifier(value = "限定識別符號")  
  2. 欄位、方法、引數  

 

(1)、根據基於XML配置中的<qualifier>標籤指定的名字進行注入,使用如下方式指定名稱:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <qualifier  type="org.springframework.beans.factory.annotation.Qualifier"  value="限定識別符號"/>  

 

其中type屬性可選,指定型別,預設就是Qualifier註解類,name就是給Bean候選者指定限定識別符號,一個Bean定義中只允許指定型別不同的<qualifier>,如果有多個相同type後面指定的將覆蓋前面的。

 

 

1、準備測試Bean:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. import javax.sql.DataSource;  
  3. import org.springframework.beans.factory.annotation.Autowired;  
  4. import org.springframework.beans.factory.annotation.Qualifier;  
  5.   
  6. public class TestBean31 {  
  7.     private DataSource dataSource;  
  8.     @Autowired  
  9.     //根據<qualifier>標籤指定Bean限定識別符號  
  10.     public void initDataSource(@Qualifier("mysqlDataSource") DataSource dataSource) {  
  11.         this.dataSource = dataSource;  
  12.     }  
  13.     public DataSource getDataSource() {  
  14.         return dataSource;  
  15.     }  
  16. }  

 

2、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="testBean31" class="cn.javass.spring.chapter12.TestBean31"/>  

 

我們使用@Qualifier("mysqlDataSource")來指定候選Bean的限定識別符號,我們需要在配置檔案中使用<qualifier>標籤來指定候選Bean的限定識別符號“mysqlDataSource”:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
  2.      <qualifier value="mysqlDataSource"/>  
  3. </bean>  

 

3、測試方法如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void testQualifierInject1() {  
  3.     TestBean31 testBean31 = ctx.getBean("testBean31", TestBean31.class);  
  4.     try {  
  5.         //使用<qualifier>指定的識別符號只能被@Qualifier使用  
  6.         ctx.getBean("mysqlDataSource");  
  7.         Assert.fail();  
  8.     } catch (Exception e) {  
  9.         //找不到該Bean  
  10.         Assert.assertTrue(e instanceof NoSuchBeanDefinitionException);  
  11.     }  
  12.      Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean31.getDataSource());  
  13. }  

從測試可以看出使用<qualifier>標籤指定的限定識別符號只能被@Qualifier使用,不能作為Bean的識別符號,如“ctx.getBean("mysqlDataSource")”是獲取不到Bean的。

 

 

(2)、預設的根據Bean名字注入:最基本方式,是在Bean上沒有指定<qualifier>標籤時一種容錯機制,即預設情況下使用Bean識別符號注入,但如果你指定了<qualifier>標籤將不會發生容錯。

 

1、準備測試Bean:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. //省略import  
  3. public class TestBean32 {  
  4.     private DataSource dataSource;  
  5.     @Autowired  
  6.     @Qualifier(value = "mysqlDataSource2"//指定Bean限定識別符號  
  7.     //@Qualifier(value = "mysqlDataSourceBean")  
  8.     //是錯誤的注入,不會發生回退容錯,因為你指定了<qualifier>  
  9.     public void initDataSource(DataSource dataSource) {  
  10.         this.dataSource = dataSource;  
  11.     }  
  12.     public DataSource getDataSource() {  
  13.         return dataSource;  
  14.     }  
  15. }  
  16.    

 

 

2、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="testBean32" class="cn.javass.spring.chapter12.TestBean32"/>  
  2. <bean id="oracleDataSource"  class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>  

 

3、測試方法如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void testQualifierInject2() {  
  3.     TestBean32 testBean32 = ctx.getBean("testBean32", TestBean32.class);  
  4.     Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean32.getDataSource());  
  5. }  

 

預設情況下(沒指定<qualifier>標籤)@Qualifier的value屬性將匹配Bean 識別符號。

 

 

(3)、擴充套件@Qualifier限定描述符註解:對@Qualifier的擴充套件來提供細粒度選擇候選者;

 

具體使用方式就是自定義一個註解並使用@Qualifier註解其即可使用。

 

首先讓我們考慮這樣一個問題,如果我們有兩個資料來源,分別為Mysql和Oracle,因此注入兩者相關資源時就牽扯到資料庫相關,如在DAO層注入SessionFactory時,當然可以採用前邊介紹的方式,但為了簡單和直觀我們希望採用自定義註解方式。

 

1、擴充套件@Qualifier限定描述符註解來分別表示Mysql和Oracle資料來源

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12.qualifier;  
  2. import org.springframework.beans.factory.annotation.Qualifier;  
  3. /** 表示注入Mysql相關 */  
  4. @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})  
  5. @Retention(RetentionPolicy.RUNTIME)  
  6. @Qualifier  
  7. public @interface Mysql {  
  8. }  

 

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12.qualifier;  
  2. import org.springframework.beans.factory.annotation.Qualifier;  
  3. /** 表示注入Oracle相關 */  
  4. @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})  
  5. @Retention(RetentionPolicy.RUNTIME)  
  6. @Qualifier  
  7. public @interface Oracle {  
  8. }  

 

 

2、準備測試Bean:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. //省略import  
  3. public class TestBean33 {  
  4.     private DataSource mysqlDataSource;  
  5.     private DataSource oracleDataSource;  
  6.     @Autowired  
  7.     public void initDataSource(@Mysql DataSource mysqlDataSource, @Oracle DataSource oracleDataSource) {  
  8.         this.mysqlDataSource = mysqlDataSource;  
  9.         this.oracleDataSource = oracleDataSource;  
  10.     }  
  11.     public DataSource getMysqlDataSource() {  
  12.         return mysqlDataSource;  
  13.     }  
  14.     public DataSource getOracleDataSource() {  
  15.         return oracleDataSource;  
  16.     }  
  17. }  

 

 

3、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="testBean33" class="cn.javass.spring.chapter12.TestBean33"/>  

 

4、在Spring修改定義的兩個資料來源:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
  2.      <qualifier value="mysqlDataSource"/>  
  3.      <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>  
  4. </bean>  
  5. <bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
  6.       <qualifier type="cn.javass.spring.chapter12.qualifier.Oracle"/>  
  7. </bean>  

 

5、測試方法如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void testQualifierInject3() {  
  3.     TestBean33 testBean33 = ctx.getBean("testBean33", TestBean33.class);  
  4.     Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean33.getMysqlDataSoruce());  
  5.     Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean33.getOracleDataSoruce());  
  6. }  

 

測試也通過了,說明我們擴充套件的@Qualifier限定描述符註解也能很好工作。

 

 

前邊演示了不帶屬性的註解,接下來演示一下帶引數的註解:

 

1、首先定義資料庫型別:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12.qualifier;  
  2. public enum DataBase {  
  3.     ORACLE, MYSQL;  
  4. }  

 

2、其次擴充套件@Qualifier限定描述符註解

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12.qualifier;  
  2. //省略import  
  3. @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})  
  4. @Retention(RetentionPolicy.RUNTIME)  
  5. @Qualifier  
  6. public @interface DataSourceType {  
  7.     String ip();      //指定ip,用於多資料來源情況  
  8.     DataBase database();//指定資料庫型別  
  9. }  

 

3、準備測試Bean:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. import javax.sql.DataSource;  
  3. import org.springframework.beans.factory.annotation.Autowired;  
  4. import cn.javass.spring.chapter12.qualifier.DataBase;  
  5. import cn.javass.spring.chapter12.qualifier.DataSourceType;  
  6. public class TestBean34 {  
  7.     private DataSource mysqlDataSource;  
  8.     private DataSource oracleDataSource;  
  9.     @Autowired  
  10.     public void initDataSource(  
  11.             @DataSourceType(ip="localhost", database=DataBase.MYSQL)  
  12.             DataSource mysqlDataSource,  
  13.             @DataSourceType(ip="localhost", database=DataBase.ORACLE)  
  14.             DataSource oracleDataSource) {  
  15.         this.mysqlDataSource = mysqlDataSource;  
  16.         this.oracleDataSource = oracleDataSource;  
  17.     }  
  18.       //省略getter方法    
  19. }  

 

4、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="testBean34" class="cn.javass.spring.chapter12.TestBean34"/>  

 

5、在Spring修改定義的兩個資料來源:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
  2.     <qualifier value="mysqlDataSource"/>  
  3.     <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>  
  4.     <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">  
  5.         <attribute key="ip" value="localhost"/>  
  6.         <attribute key="database" value="MYSQL"/>  
  7.     </qualifier>  
  8. </bean>  
  9. <bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
  10.     <qualifier type="cn.javass.spring.chapter12.qualifier.Oracle"/>  
  11.     <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">  
  12.         <attribute key="ip" value="localhost"/>  
  13.         <attribute key="database" value="ORACLE"/>  
  14.     </qualifier>  
  15. </bean>  

 

6、測試方法如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void testQualifierInject3() {  
  3.     TestBean34 testBean34 = ctx.getBean("testBean34", TestBean34.class);  
  4.     Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean34.getMysqlDataSource());  
  5.     Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean34.getOracleDataSoruce());  
  6. }  

  測試也通過了,說明我們擴充套件的@Qualifier限定描述符註解也能很好工作。

 

  

 

四、自定義註解限定描述符:完全不使用@Qualifier,而是自己定義一個獨立的限定註解;

 

1、首先使用如下方式定義一個自定義註解限定描述符:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12.qualifier;  
  2. //省略import  
  3. @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})  
  4. @Retention(RetentionPolicy.RUNTIME)  
  5. public @interface CustomQualifier {  
  6.     String value();  
  7. }  

 

 

2、準備測試Bean:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. //省略import  
  3. public class TestBean35 {  
  4.     private DataSource dataSoruce;  
  5.     @Autowired  
  6.     public TestBean35(@CustomQualifier("oracleDataSource") DataSource dataSource) {  
  7.         this.dataSoruce = dataSource;  
  8.     }  
  9.     public DataSource getDataSoruce() {  
  10.         return dataSoruce;  
  11.     }  
  12. }  

 

3、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="testBean35" class="cn.javass.spring.chapter12.TestBean35"/>  

 

4、然後在Spring配置檔案中註冊CustomQualifier自定義註解限定描述符,只有註冊了Spring才能識別:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="customAutowireConfigurer" class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">  
  2.     <property name="customQualifierTypes">  
  3.         <set>  
  4.             <value>cn.javass.spring.chapter12.qualifier.CustomQualifier</value>  
  5.         </set>  
  6.    </property>  
  7. </bean>  

 

5、測試方法如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void testQualifierInject5() {  
  3.     TestBean35 testBean35 = ctx.getBean("testBean35", TestBean35.class);  
  4.     Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean35.getDataSource());  
  5. }  

    從測試中可看出,自定義的和Spring自帶的沒什麼區別,因此如果沒有足夠的理由請使用Spring自帶的Qualifier註解。

 

    到此限定描述符介紹完畢,在此一定要注意以下幾點:

  • 限定識別符號和Bean的描述符是不一樣的;
  • 多個Bean定義中可以使用相同的限定識別符號;
  • 對於集合、陣列、字典型別的限定描述符注入,將注入多個具有相同限定識別符號的Bean。

 

 

 

 

12.2.3  JSR-250註解

一、@Resource:自動裝配,預設根據型別裝配,如果指定name屬性將根據名字裝配,可以使用如下方式來指定:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Resource(name = "識別符號")  
  2. 欄位或setter方法  

 

1、準備測試Bean:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. import javax.annotation.Resource;  
  3. public class TestBean41 {  
  4.     @Resource(name = "message")  
  5.     private String message;  
  6.     //省略getter和setter  
  7. }  

 

 

2、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="testBean41" class="cn.javass.spring.chapter12.TestBean41"/>  

 

3、測試方法如下: 

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void testResourceInject1() {  
  3.     TestBean41 testBean41 = ctx.getBean("testBean41", TestBean41.class);  
  4.     Assert.assertEquals("hello", testBean41.getMessage());  
  5. }  

    使用非常簡單,和@Autowired不同的是可以指定name來根據名字注入。

 

    使用@Resource需要注意以下幾點:

  • @Resource註解應該只用於setter方法注入,不能提供如@Autowired多引數方法注入;
  • @Resource在沒有指定name屬性的情況下首先將根據setter方法對於的欄位名查詢資源,如果找不到再根據型別查詢;
  • @Resource首先將從JNDI環境中查詢資源,如果沒找到預設再到Spring容器中查詢,因此如果JNDI環境中有和Spring容器同名的資源時需要注意。

 

 

二、@PostConstruct和PreDestroy:通過註解指定初始化和銷燬方法定義;

 

1、在測試類TestBean41中新增如下程式碼:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @PostConstruct  
  2. public void init() {  
  3.     System.out.println("==========init");  
  4. }  
  5. @PreDestroy  
  6. public void destroy() {  
  7.     System.out.println("==========destroy");  
  8. }  

 

2、修改測試方法如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void resourceInjectTest1() {  
  3.     ((ClassPathXmlApplicationContext) ctx).registerShutdownHook();  
  4.     TestBean41 testBean41 = ctx.getBean("testBean41", TestBean41.class);  
  5.     Assert.assertEquals("hello", testBean41.getMessage());  
  6. }  

    類似於通過<bean>標籤的init-method和destroy-method屬性指定的初始化和銷燬方法,但具有更高優先順序,即註解方式的初始化和銷燬方法將先執行。

 

 

12.2.4  JSR-330註解

在測試之前需要準備JSR-330註解所需要的jar包,到spring-framework-3.0.5.RELEASE-dependencies.zip中拷貝如下jar包到類路徑:

 

com.springsource.javax.inject-1.0.0.jar

 

       一、@Inject:等價於預設的@Autowired,只是沒有required屬性;

       二、@Named:指定Bean名字,對應於Spring自帶@Qualifier中的預設的根據Bean名字注入情況;

       三、@Qualifier:只對應於Spring自帶@Qualifier中的擴充套件@Qualifier限定描述符註解,即只能擴充套件使用,沒有value屬性。

 

 

1、首先擴充套件@Qualifier限定描述符註解來表示Mysql資料來源

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12.qualifier;  
  2. //省略部分import  
  3. import javax.inject.Qualifier;  
  4. @Target({ElementType.FIELD, ElementType.PARAMETER})  
  5. @Retention(RetentionPolicy.RUNTIME)  
  6. @Qualifier  
  7. public @interface JSR330Mysql {  
  8. }  
  9.    

 

 

2、準備測試Bean:

 

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. import javax.inject.Inject;  
  3. import javax.inject.Named;  
  4. import javax.sql.DataSource;  
  5. import cn.javass.spring.chapter12.qualifier.JSR330Mysql;  
  6. public class TestBean51 {  
  7.     private DataSource mysqlDataSource;  
  8.     private DataSource oracleDataSource;  
  9.     @Inject  
  10.     public void initDataSoruce(  
  11.             @JSR330Mysql  DataSource mysqlDataSource,  
  12.             @Named("oracleDataSource") DataSource oracleDataSource) {  
  13.         this.mysqlDataSource = mysqlDataSource;  
  14.         this.oracleDataSource = oracleDataSource;  
  15.   
  16.     }  
  17.     //省略getter    
  18. }  

 

3、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="testBean51" class="cn.javass.spring.chapter12.TestBean51"/>  

 

4、在Spring修改定義的mysqlDataSourceBean資料來源:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
  2.          <qualifier value="mysqlDataSource"/>  
  3.          <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>  
  4.          <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">  
  5.              <attribute key="ip" value="localhost"/>  
  6.              <attribute key="database" value="MYSQL"/>  
  7.          </qualifier>  
  8.          <qualifier type="cn.javass.spring.chapter12.qualifier.JSR330Mysql"/>  
  9. </bean>  

 

 

5、測試方法如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void testInject() {  
  3.     TestBean51 testBean51 = ctx.getBean("testBean51", TestBean51.class);  
  4.     Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean51.getMysqlDataSource());  
  5.     Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean51.getOracleDataSource());  
  6. }  

 

 

測試也通過了,說明JSR-330註解也能很好工作。

 

從測試中可以看出JSR-330註解和Spring自帶註解依賴注入時主要有以下特點:

  • Spring自帶的@Autowired的預設情況等價於JSR-330的@Inject註解;
  • Spring自帶的@Qualifier的預設的根據Bean名字注入情況等價於JSR-330的@Named註解;
  • Spring自帶的@Qualifier的擴充套件@Qualifier限定描述符註解情況等價於JSR-330的@Qualifier註解。

 

 

 

5  JPA註解

用於注入EntityManagerFactory和EntityManager。

      

1、準備測試Bean:

 

java程式碼:
Java程式碼  收藏程式碼
  1. package cn.javass.spring.chapter12;  
  2. //省略import  
  3. public class TestBean61 {  
  4.     @PersistenceContext(unitName = "entityManagerFactory")  
  5.     private EntityManager entityManager;  
  6.      
  7.     @PersistenceUnit(unitName = "entityManagerFactory")  
  8.     private EntityManagerFactory entityManagerFactory;  
  9.      
  10.     public EntityManager getEntityManager() {  
  11.         return entityManager;  
  12.     }  
  13.     public EntityManagerFactory getEntityManagerFactory() {  
  14.         return entityManagerFactory;  
  15.     }  
  16. }  

 

2、在Spring配置檔案(chapter12/dependecyInjectWithAnnotation.xml)新增如下Bean配置:

 

java程式碼:
Java程式碼  收藏程式碼
  1. <import resource="classpath:chapter7/applicationContext-resources.xml"/>  
  2. <import resource="classpath:chapter8/applicationContext-jpa.xml"/>  
  3. <bean id="testBean61" class="cn.javass.spring.chapter12.TestBean61"/>  

    此處需要引用第七章和八章的配置檔案,細節內容請參考七八兩章。

 

 

3、測試方法如下:

 

java程式碼:
Java程式碼  收藏程式碼
  1. @Test  
  2. public void testJpaInject() {  
  3.     TestBean61 testBean61 = ctx.getBean("testBean61", TestBean61.class);  
  4.     Assert.assertNotNull(testBean61.getEntityManager());  
  5.     Assert.assertNotNull(testBean61.getEntityManagerFactory());  
  6. }  

    測試也通過了,說明JPA註解也能很好工作。

 

JPA註解類似於@Resource註解同樣是先根據unitName屬性去JNDI環境中查詢,如果沒找到在到Spring容器中查詢。




 6. 在spring 3.0中,可以通過使用@value,對一些如xxx.properties檔案中的檔案,進行鍵值對的注入,例子如下:

1.首先在applicationContext.xml中中加入: 
XML程式碼  收藏程式碼
  1. beans  xmlns = “http://www.springframework.org/schema/beans”  
  2.     xmlns:xsi = “http://www.w3.org/2001/XMLSchema-instance”  
  3.         xsi:schemaLocation =“http://www.springframework.org/schema/beans   
  4.          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd“ >  
 的名稱空間,然後
2。
XML程式碼  收藏程式碼
  1. bean  id = “propertyConfigurer”  class = “org.springframework.beans.factory.config.PropertyPlaceholderConfigurer” >    
  2.     property  name = “locations” >    
  3.         list >    
  4.             value > classpath:test.properties </ value >    
  5.         </ list >                
  6.     </ property >                                
  7. </ bean >  

建立test.properties  
   abc = 123  

4。
的Java程式碼  收藏程式碼
  1. import  org.springframework.beans.factory.annotation.Value;     
  2. import  org.springframework.stereotype.Controller;     
  3. import  org.springframework.web.bind.annotation.RequestMapping;     
  4.     
  5. @RequestMapping“/ admin / images”)     
  6. @Controller     
  7. public  class  ImageAdminController {     
  8.     
  9.     private  String imageDir;     
  10.       
  11.     @Value“$ {abc}”)   
  12.     public  void  setImageDir(String val){     
  13.         這個 .imageDir = val     
  14.     }  
  15. }  
        這樣就將test.abc的值注入了IMAGEDIR中了。
 
 

有時候需要從屬性檔案中載入配置,以前的方式是這樣的:

 

HTML程式碼  收藏程式碼
  1. bean id “jdbcProperties” class “org.springframework.beans.factory.config.PropertyPlaceholderConfigurer” >    
  2.     property name = “locations” >   
  3.         list >  
  4.             value classpath *:/ spring / jdbc.properties </ value >  
  5.         </ list >  
  6.     </ property >  
  7. </ bean >  

最近發現這樣也可以,程式碼更整潔:

 

HTML程式碼  收藏程式碼
  1. context:property-placeholder location “classpath:spring / jdbc.properties” />    

在豆定義中依然可以通過“$ {}”這種方式來去值:

 

HTML程式碼  收藏程式碼
  1. bean id “dataSource” class “org.apache.commons.dbcp.BasicDataSource” >    
  2.         property name “driverClassName” value “$ {jdbc.driverClassName}” />     
  3.         property name “url” value “$ {jdbc.url}” />     
  4.         property name “username” value “$ {jdbc.username}” />     
  5.         property name “password” value “$ {jdbc.password}” />     
  6.         property name “initialSize” value “$ {jdbc.initialSize}” />     
  7.         property name “maxActive” value “$ {jdbc.maxActive}” />     
  8.         property name “maxIdle” value “$ {jdbc.maxIdle}” />     
  9.         property name “minIdle” value “$ {jdbc.minIdle}” />     
  10.     </ bean >  

<context:property-placeholder ... /> 是與PropertyPlaceholderConfigurer相當的XML。所以,喜歡 在  <util:properties/> 簡單的工廠一個java.util.Properties例項可以注入。


  在spring 3.0中,可以通過使用@value,對一些如xxx.properties檔案中的檔案,進行鍵值對的注入,例子如下:

1.首先在applicationContext.xml中中加入: 
XML程式碼  收藏程式碼
  1. beans  xmlns = “http://www.springframework.org/schema/beans”  
  2.     xmlns:xsi = “http://www.w3.org/2001/XMLSchema-instance”  
  3.         xsi:schemaLocation =“http://www.springframework.org/schema/beans   
  4.          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd“ >  
 的名稱空間,然後
2。
XML程式碼  收藏程式碼
  1. bean  id = “propertyConfigurer”  class = “org.springframework.beans.factory.config.PropertyPlaceholderConfigurer” >    
  2.     property  name = “locations” >    
  3.         list >    
  4.             value > classpath:test.properties </ value >    
  5.         </ list >                
  6.     </ property >                                
  7. </ bean >  

建立test.properties  
   abc = 123  

4。
的Java程式碼  收藏程式碼
  1. import  org.springframework.beans.factory.annotation.Value;     
  2. import  org.springframework.stereotype.Controller;     
  3. import  org.springframework.web.bind.annotation.RequestMapping;     
  4.     
  5. @RequestMapping“/ admin / images”)     
  6. @Controller     
  7. public  class  ImageAdminController {     
  8.     
  9.     private  String imageDir;     
  10.       
  11.     @Value“$ {abc}”)   
  12.     public  void  setImageDir(String val){     
  13.         這個 .imageDir = val     
  14.     }  
  15. }  
        這樣就將test.abc的值注入了IMAGEDIR中了。
 
 

有時候需要從屬性檔案中載入配置,以前的方式是這樣的:

 

HTML程式碼  收藏程式碼
  1. bean id “jdbcProperties” class “org.springframework.beans.factory.config.PropertyPlaceholderConfigurer” >    
  2.     property name = “locations” >   
  3.         list >  
  4.             value classpath *:/ spring / jdbc.properties </ value >  
  5.         </ list >  
  6.     </ property >  
  7. </ bean >  

最近發現這樣也可以,程式碼更整潔:

 

HTML程式碼  收藏程式碼
  1. context:property-placeholder location “classpath:spring / jdbc.properties” />    

在豆定義中依然可以通過“$ {}”這種方式來去值:

 

HTML程式碼  收藏程式碼
  1. bean id “dataSource” class “org.apache.commons.dbcp.BasicDataSource” >    
  2.         property name “driverClassName” value “$ {jdbc.driverClassName}” />     
  3.         property name “url” value “$ {jdbc.url}” />     
  4.         property name “username” value “$ {jdbc.username}” />     
  5.         property name “password” value “$ {jdbc.password}” />     
  6.         property name “initialSize” value “$ {jdbc.initialSize}” />     
  7.         property name “maxActive” value “$ {jdbc.maxActive}” />     
  8.         property name “maxIdle” value “$ {jdbc.maxIdle}” />     
  9.         property name “minIdle” value “$ {jdbc.minIdle}” />     
  10.     </ bean >  

<context:property-placeholder ... /> 是與PropertyPlaceholderConfigurer相當的XML。所以,喜歡 在  <util:properties/> 簡單的工廠一個java.util.Properties例項可以注入。

相關文章