Spring零配置通過註解實現Bean依賴註入總結 – JAVA編程語言程序開發技術文章

12.2  註解實現Bean依賴註入
12.2.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代碼    
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.   
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation=" http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:annotation-config/>

</beans>
 
 
   這樣就能使用註解驅動依賴註入瞭,該配置文件位於“resources/ chapter12/dependecyInjectWithAnnotation.xml”。
 
12.2.2  Spring自帶依賴註入註解
一、@Required:依賴檢查;
對應於基於XML配置中的依賴檢查,但XML配置的依賴檢查將檢查所有setter方法,詳見【3.3.4  依賴檢查】;
基於@Required的依賴檢查表示註解的setter方法必須,即必須通過在XML配置中配置setter註入,如果沒有配置在容器啟動時會拋出異常從而保證在運行時不會遇到空指針異常,@Required隻能放置在setter方法上,且通過XML配置的setter註入,可以使用如下方式來指定:
 

Java代碼    
1. @Requried 
2. setter方法 
@Requried
setter方法
 
1、準備測試Bean
 

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. } 
package cn.javass.spring.chapter12;
public class TestBean {
    private String message;
    @Required
    public void setMessage(String message) {
        this.message = message;
    }
    public String getMessage() {
        return message;
    }
}
 
 
2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

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> 
<bean id="testBean" class="cn.javass.spring.chapter12.TestBean">
<property name="message" ref="message"/>
</bean>
<bean id="message" class="java.lang.String">
    <constructor-arg index="0" value="hello"/>
</bean>
 
3、測試類和測試方法如下:
 

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. } 
package cn.javass.spring.chapter12;
//省略import
public class DependencyInjectWithAnnotationTest {
    private static String configLocation = "classpath:chapter12/dependecyInjectWithAnnotation.xml";
    private static ApplicationContext ctx = new ClassPathXmlApplicationContext("configLocation");
    //1、Spring自帶依賴註入註解
     @Test
    public void testRequiredForXmlSetterInject() {
        TestBean testBean = ctx.getBean("testBean", TestBean.class);
        Assert.assertEquals("hello", testBean.getMessage());
    }
}
 
在XML配置文件中必須指定setter註入,否則在Spring容器啟動時將拋出如下異常:
 

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' 
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'testBean' defined in class path resource [chapter12/dependecyInjectWithAnnotation.xml]: Initialization of bean failed;
nested exception is org.springframework.beans.factory.BeanInitializationException: Property 'message' is required for bean 'testBean'
 
 
 
 
二、@Autowired:自動裝配
自動裝配,用於替代基於XML配置的自動裝配,詳見【3.3.3  自動裝配】。
 
基於@Autowired的自動裝配,默認是根據類型註入,可以用於構造器、字段、方法註入,使用方式如下:
 

Java代碼    
1. @Autowired(required=true)  
2. 構造器、字段、方法 
@Autowired(required=true)
構造器、字段、方法
 
@Autowired默認是根據參數類型進行自動裝配,且必須有一個Bean候選者註入,如果允許出現0個Bean候選者需要設置屬性“required=false”,“required”屬性含義和@Required一樣,隻是@Required隻適用於基於XML配置的setter註入方式。
 
(1)、構造器註入:通過將@Autowired註解放在構造器上來完成構造器註入,默認構造器參數通過類型自動裝配,如下所示:
 
1、準備測試Bean,在構造器上添加@AutoWired註解:
 

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. } 
package cn.javass.spring.chapter12;
import org.springframework.beans.factory.annotation.Autowired;
public class TestBean11 {
    private String message;
    @Autowired //構造器註入
    private TestBean11(String message) {
        this.message = message;
    }
    //省略message的getter和setter
}
 
 
2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

Java代碼    
1. <bean id="testBean11" class="cn.javass.spring.chapter12.TestBean11"/> 
<bean id="testBean11" class="cn.javass.spring.chapter12.TestBean11"/>
 
3、測試類如下:
 

Java代碼    
1. @Test 
2. public void testAutowiredForConstructor() {  
3.     TestBean11 testBean11 = ctx.getBean("testBean11", TestBean11.class);  
4.     Assert.assertEquals("hello", testBean11.getMessage());  
5. } 
@Test
public void testAutowiredForConstructor() {
    TestBean11 testBean11 = ctx.getBean("testBean11", TestBean11.class);
    Assert.assertEquals("hello", testBean11.getMessage());
}
    在Spring配置文件中沒有對“testBean11”進行構造器註入和setter註入配置,而是通過在構造器上添加@ Autowired來完成根據參數類型完成構造器註入。
 
 
 
(2)、字段註入:通過將@Autowired註解放在構造器上來完成字段註入。
 
1、準備測試Bean,在字段上添加@AutoWired註解:
 

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. } 
package cn.javass.spring.chapter12;
import org.springframework.beans.factory.annotation.Autowired;
public class TestBean12 {
    @Autowired //字段註入
    private String message;
    //省略getter和setter
}
 
 
2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

Java代碼    
1. <bean id="testBean12" class="cn.javass.spring.chapter12.TestBean12"/> 
<bean id="testBean12" class="cn.javass.spring.chapter12.TestBean12"/>
 
3、測試方法如下:
 

Java代碼    
1. @Test 
2. public void testAutowiredForField() {  
3.     TestBean12 testBean12 = ctx.getBean("testBean12", TestBean12.class);  
4.     Assert.assertEquals("hello", testBean12.getMessage());  
5. } 
@Test
public void testAutowiredForField() {
    TestBean12 testBean12 = ctx.getBean("testBean12", TestBean12.class);
    Assert.assertEquals("hello", testBean12.getMessage());
}
    字段註入在基於XML配置中無相應概念,字段註入不支持靜態類型字段的註入。
 
 
(3)、方法參數註入:通過將@Autowired註解放在方法上來完成方法參數註入。
 
1、準備測試Bean,在方法上添加@AutoWired註解:
 

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. } 
package cn.javass.spring.chapter12;
import org.springframework.beans.factory.annotation.Autowired;
public class TestBean13 {
    private String message;
    @Autowired //setter方法註入
    public void setMessage(String message) {
        this.message = message;
    }
    public String getMessage() {
        return message;
    }
}
 
 
 

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. } 
package cn.javass.spring.chapter12;
//省略import
public class TestBean14 {
    private String message;
    private List<String> list;
    @Autowired(required = true) //任意一個或多個參數方法註入
    private void initMessage(String message, ArrayList<String> list) {
        this.message = message;
        this.list = list;
    }
    //省略getter和setter
}
 
2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

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> 
<bean id="testBean13" class="cn.javass.spring.chapter12.TestBean13"/>
<bean id="testBean14" class="cn.javass.spring.chapter12.TestBean14"/>
<bean id="list" class="java.util.ArrayList">
    <constructor-arg index="0">
        <list>
            <ref bean="message"/>
            <ref bean="message"/>
        </list>
   </constructor-arg>       
</bean>
 
3、測試方法如下:
 

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.   
@Test
public void testAutowiredForMethod() {
    TestBean13 testBean13 = ctx.getBean("testBean13", TestBean13.class);
    Assert.assertEquals("hello", testBean13.getMessage());
 
    TestBean14 testBean14 = ctx.getBean("testBean14", TestBean14.class);
    Assert.assertEquals("hello", testBean14.getMessage());
    Assert.assertEquals(ctx.getBean("list", List.class), testBean14.getList());
}
 
 
方法參數註入除瞭支持setter方法註入,還支持1個或多個參數的普通方法註入,在基於XML配置中不支持1個或多個參數的普通方法註入,方法註入不支持靜態類型方法的註入。
 
註意“initMessage(String message, ArrayList<String> list)”方法簽名中為什麼使用ArrayList而不是List呢?具體參考【3.3.3  自動裝配】一節中的集合類型註入區別。
 
 
 
 
 
三、@Value:註入SpEL表達式;
 
用於註入SpEL表達式,可以放置在字段方法或參數上,使用方式如下:
 

Java代碼    
1. @Value(value = "SpEL表達式")  
2. 字段、方法、參數 
@Value(value = "SpEL表達式")
字段、方法、參數
 
1、可以在類字段上使用該註解:
 

Java代碼    
1. @Value(value = "#{message}")  
2. private String message; 
@Value(value = "#{message}")
private String message;
 
2、可以放置在帶@Autowired註解的方法的參數上:
 

Java代碼    
1. @Autowired 
2. public void initMessage(@Value(value = "#{message}#{message}") String message) {  
3.     this.message = message;  
4. } 
@Autowired
public void initMessage(@Value(value = "#{message}#{message}") String message) {
    this.message = message;
}
 
3、還可以放置在帶@Autowired註解的構造器的參數上:
 

Java代碼    
1. @Autowired 
2. private TestBean43(@Value(value = "#{message}#{message}") String message) {  
3.     this.message = message;  
4. } 
@Autowired
private TestBean43(@Value(value = "#{message}#{message}") String message) {
    this.message = message;
}
    具體測試詳見DependencyInjectWithAnnotationTest 類的testValueInject測試方法。
 
 
 
 
四、@Qualifier:限定描述符,用於細粒度選擇候選者;
 
@Autowired默認是根據類型進行註入的,因此如果有多個類型一樣的Bean候選者,則需要限定其中一個候選者,否則將拋出異常,詳見【3.3.3  自動裝配】中的根據類型進行註入;
 
@Qualifier限定描述符除瞭能根據名字進行註入,但能進行更細粒度的控制如何選擇候選者,具體使用方式如下:
 

Java代碼    
1. @Qualifier(value = "限定標識符")  
2. 字段、方法、參數 
@Qualifier(value = "限定標識符")
字段、方法、參數
 
(1)、根據基於XML配置中的<qualifier>標簽指定的名字進行註入,使用如下方式指定名稱:
 

Java代碼    
1. <qualifier  type="org.springframework.beans.factory.annotation.Qualifier"  value="限定標識符"/> 
<qualifier  type="org.springframework.beans.factory.annotation.Qualifier"  value="限定標識符"/>
 
其中type屬性可選,指定類型,默認就是Qualifier註解類,name就是給Bean候選者指定限定標識符,一個Bean定義中隻允許指定類型不同的<qualifier>,如果有多個相同type後面指定的將覆蓋前面的。
 
 
1、準備測試Bean:
 

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. } 
package cn.javass.spring.chapter12;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class TestBean31 {
    private DataSource dataSource;
    @Autowired
    //根據<qualifier>標簽指定Bean限定標識符
    public void initDataSource(@Qualifier("mysqlDataSource") DataSource dataSource) {
        this.dataSource = dataSource;
    }
    public DataSource getDataSource() {
        return dataSource;
    }
}
 
2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

Java代碼    
1. <bean id="testBean31" class="cn.javass.spring.chapter12.TestBean31"/> 
<bean id="testBean31" class="cn.javass.spring.chapter12.TestBean31"/>
 
我們使用@Qualifier("mysqlDataSource")來指定候選Bean的限定標識符,我們需要在配置文件中使用<qualifier>標簽來指定候選Bean的限定標識符“mysqlDataSource”:
 

Java代碼    
1. <bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
2.      <qualifier value="mysqlDataSource"/>  
3. </bean> 
<bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     <qualifier value="mysqlDataSource"/>
</bean>
 
3、測試方法如下:
 

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. } 
@Test
public void testQualifierInject1() {
    TestBean31 testBean31 = ctx.getBean("testBean31", TestBean31.class);
    try {
        //使用<qualifier>指定的標識符隻能被@Qualifier使用
        ctx.getBean("mysqlDataSource");
        Assert.fail();
    } catch (Exception e) {
        //找不到該Bean
        Assert.assertTrue(e instanceof NoSuchBeanDefinitionException);
    }
     Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean31.getDataSource());
}
從測試可以看出使用<qualifier>標簽指定的限定標識符隻能被@Qualifier使用,不能作為Bean的標識符,如“ctx.getBean("mysqlDataSource")”是獲取不到Bean的。
 
 
(2)、缺省的根據Bean名字註入:最基本方式,是在Bean上沒有指定<qualifier>標簽時一種容錯機制,即缺省情況下使用Bean標識符註入,但如果你指定瞭<qualifier>標簽將不會發生容錯。
 
1、準備測試Bean:
 

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.   
package cn.javass.spring.chapter12;
//省略import
public class TestBean32 {
    private DataSource dataSource;
    @Autowired
    @Qualifier(value = "mysqlDataSource2") //指定Bean限定標識符
    //@Qualifier(value = "mysqlDataSourceBean")
    //是錯誤的註入,不會發生回退容錯,因為你指定瞭<qualifier>
    public void initDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    public DataSource getDataSource() {
        return dataSource;
    }
}
 
 
 
2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

Java代碼    
1. <bean id="testBean32" class="cn.javass.spring.chapter12.TestBean32"/>  
2. <bean id="oracleDataSource"  class="org.springframework.jdbc.datasource.DriverManagerDataSource"/> 
<bean id="testBean32" class="cn.javass.spring.chapter12.TestBean32"/>
<bean id="oracleDataSource"  class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
 
3、測試方法如下:
 

Java代碼    
1. @Test 
2. public void testQualifierInject2() {  
3.     TestBean32 testBean32 = ctx.getBean("testBean32", TestBean32.class);  
4.     Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean32.getDataSource());  
5. } 
@Test
public void testQualifierInject2() {
    TestBean32 testBean32 = ctx.getBean("testBean32", TestBean32.class);
    Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean32.getDataSource());
}
 
默認情況下(沒指定<qualifier>標簽)@Qualifier的value屬性將匹配Bean 標識符。
 
 
(3)、擴展@Qualifier限定描述符註解:對@Qualifier的擴展來提供細粒度選擇候選者;
 
具體使用方式就是自定義一個註解並使用@Qualifier註解其即可使用。
 
首先讓我們考慮這樣一個問題,如果我們有兩個數據源,分別為Mysql和Oracle,因此註入兩者相關資源時就牽扯到數據庫相關,如在DAO層註入SessionFactory時,當然可以采用前邊介紹的方式,但為瞭簡單和直觀我們希望采用自定義註解方式。
 
1、擴展@Qualifier限定描述符註解來分別表示Mysql和Oracle數據源
 

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. } 
package cn.javass.spring.chapter12.qualifier;
import org.springframework.beans.factory.annotation.Qualifier;
/** 表示註入Mysql相關 */
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Mysql {
}
 
 

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. } 
package cn.javass.spring.chapter12.qualifier;
import org.springframework.beans.factory.annotation.Qualifier;
/** 表示註入Oracle相關 */
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Oracle {
}
 
 
2、準備測試Bean:
 

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. } 
package cn.javass.spring.chapter12;
//省略import
public class TestBean33 {
    private DataSource mysqlDataSource;
    private DataSource oracleDataSource;
    @Autowired
    public void initDataSource(@Mysql DataSource mysqlDataSource, @Oracle DataSource oracleDataSource) {
        this.mysqlDataSource = mysqlDataSource;
        this.oracleDataSource = oracleDataSource;
    }
    public DataSource getMysqlDataSource() {
        return mysqlDataSource;
    }
    public DataSource getOracleDataSource() {
        return oracleDataSource;
    }
}
 
 
3、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

Java代碼    
1. <bean id="testBean33" class="cn.javass.spring.chapter12.TestBean33"/> 
<bean id="testBean33" class="cn.javass.spring.chapter12.TestBean33"/>
 
4、在Spring修改定義的兩個數據源:
 

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> 
<bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     <qualifier value="mysqlDataSource"/>
     <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>
</bean>
<bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <qualifier type="cn.javass.spring.chapter12.qualifier.Oracle"/>
</bean>
 
5、測試方法如下:
 

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. } 
@Test
public void testQualifierInject3() {
    TestBean33 testBean33 = ctx.getBean("testBean33", TestBean33.class);
    Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean33.getMysqlDataSoruce());
    Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean33.getOracleDataSoruce());
}
 
測試也通過瞭,說明我們擴展的@Qualifier限定描述符註解也能很好工作。
 
 
前邊演示瞭不帶屬性的註解,接下來演示一下帶參數的註解:
 
1、首先定義數據庫類型:
 

Java代碼    
1. package cn.javass.spring.chapter12.qualifier;  
2. public enum DataBase {  
3.     ORACLE, MYSQL;  
4. } 
package cn.javass.spring.chapter12.qualifier;
public enum DataBase {
    ORACLE, MYSQL;
}
 
2、其次擴展@Qualifier限定描述符註解
 

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. } 
package cn.javass.spring.chapter12.qualifier;
//省略import
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface DataSourceType {
    String ip();      //指定ip,用於多數據源情況
    DataBase database();//指定數據庫類型
}
 
3、準備測試Bean:
 

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. } 
package cn.javass.spring.chapter12;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import cn.javass.spring.chapter12.qualifier.DataBase;
import cn.javass.spring.chapter12.qualifier.DataSourceType;
public class TestBean34 {
    private DataSource mysqlDataSource;
    private DataSource oracleDataSource;
    @Autowired
    public void initDataSource(
            @DataSourceType(ip="localhost", database=DataBase.MYSQL)
            DataSource mysqlDataSource,
            @DataSourceType(ip="localhost", database=DataBase.ORACLE)
            DataSource oracleDataSource) {
        this.mysqlDataSource = mysqlDataSource;
        this.oracleDataSource = oracleDataSource;
    }
      //省略getter方法 
}
 
4、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

Java代碼    
1. <bean id="testBean34" class="cn.javass.spring.chapter12.TestBean34"/> 
<bean id="testBean34" class="cn.javass.spring.chapter12.TestBean34"/>
 
5、在Spring修改定義的兩個數據源:
 

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> 
<bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <qualifier value="mysqlDataSource"/>
    <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>
    <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">
        <attribute key="ip" value="localhost"/>
        <attribute key="database" value="MYSQL"/>
    </qualifier>
</bean>
<bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <qualifier type="cn.javass.spring.chapter12.qualifier.Oracle"/>
    <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">
        <attribute key="ip" value="localhost"/>
        <attribute key="database" value="ORACLE"/>
    </qualifier>
</bean>
 
6、測試方法如下:
 

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. } 
@Test
public void testQualifierInject3() {
    TestBean34 testBean34 = ctx.getBean("testBean34", TestBean34.class);
    Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean34.getMysqlDataSource());
    Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean34.getOracleDataSoruce());
}
  測試也通過瞭,說明我們擴展的@Qualifier限定描述符註解也能很好工作。
 
 
 
四、自定義註解限定描述符:完全不使用@Qualifier,而是自己定義一個獨立的限定註解;
 
1、首先使用如下方式定義一個自定義註解限定描述符:
 

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. } 
package cn.javass.spring.chapter12.qualifier;
//省略import
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomQualifier {
    String value();
}
 
 
2、準備測試Bean:
 

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. } 
package cn.javass.spring.chapter12;
//省略import
public class TestBean35 {
    private DataSource dataSoruce;
    @Autowired
    public TestBean35(@CustomQualifier("oracleDataSource") DataSource dataSource) {
        this.dataSoruce = dataSource;
    }
    public DataSource getDataSoruce() {
        return dataSoruce;
    }
}
 
3、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

Java代碼    
1. <bean id="testBean35" class="cn.javass.spring.chapter12.TestBean35"/> 
<bean id="testBean35" class="cn.javass.spring.chapter12.TestBean35"/>
 
4、然後在Spring配置文件中註冊CustomQualifier自定義註解限定描述符,隻有註冊瞭Spring才能識別:
 

Java代碼    
1. <bean id="customAutowireConfigurer" class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">  
2.     <property name="customQualifierTypes" _cke_saved_name="customQualifierTypes">  
3.         <set>  
4.             <value>cn.javass.spring.chapter12.qualifier.CustomQualifier</value>  
5.         </set>  
6.    </property>  
7. </bean> 
<bean id="customAutowireConfigurer" class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
    <property name="customQualifierTypes">
        <set>
            <value>cn.javass.spring.chapter12.qualifier.CustomQualifier</value>
        </set>
   </property>
</bean>
 
5、測試方法如下:
 

Java代碼    
1. @Test 
2. public void testQualifierInject5() {  
3.     TestBean35 testBean35 = ctx.getBean("testBean35", TestBean35.class);  
4.     Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean35.getDataSource());  
5. } 
@Test
public void testQualifierInject5() {
    TestBean35 testBean35 = ctx.getBean("testBean35", TestBean35.class);
    Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean35.getDataSource());
}
    從測試中可看出,自定義的和Spring自帶的沒什麼區別,因此如果沒有足夠的理由請使用Spring自帶的Qualifier註解。
 
    到此限定描述符介紹完畢,在此一定要註意以下幾點:
• 限定標識符和Bean的描述符是不一樣的;
• 多個Bean定義中可以使用相同的限定標識符;
• 對於集合、數組、字典類型的限定描述符註入,將註入多個具有相同限定標識符的Bean。
 
 
 
 
12.2.3  JSR-250註解
一、@Resource:自動裝配,默認根據類型裝配,如果指定name屬性將根據名字裝配,可以使用如下方式來指定:
 

Java代碼    
1. @Resource(name = "標識符")  
2. 字段或setter方法 
@Resource(name = "標識符")
字段或setter方法
 
1、準備測試Bean:
 

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. } 
package cn.javass.spring.chapter12;
import javax.annotation.Resource;
public class TestBean41 {
    @Resource(name = "message")
    private String message;
    //省略getter和setter
}
 
 
2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

Java代碼    
1. <bean id="testBean41" class="cn.javass.spring.chapter12.TestBean41"/> 
<bean id="testBean41" class="cn.javass.spring.chapter12.TestBean41"/>
 
3、測試方法如下:
 

Java代碼    
1. @Test 
2. public void testResourceInject1() {  
3.     TestBean41 testBean41 = ctx.getBean("testBean41", TestBean41.class);  
4.     Assert.assertEquals("hello", testBean41.getMessage());  
5. } 
@Test
public void testResourceInject1() {
    TestBean41 testBean41 = ctx.getBean("testBean41", TestBean41.class);
    Assert.assertEquals("hello", testBean41.getMessage());
}
    使用非常簡單,和@Autowired不同的是可以指定name來根據名字註入。
 
    使用@Resource需要註意以下幾點:
• @Resource註解應該隻用於setter方法註入,不能提供如@Autowired多參數方法註入;
• @Resource在沒有指定name屬性的情況下首先將根據setter方法對於的字段名查找資源,如果找不到再根據類型查找;
• @Resource首先將從JNDI環境中查找資源,如果沒找到默認再到Spring容器中查找,因此如果JNDI環境中有和Spring容器同名的資源時需要註意。
 
 
二、@PostConstruct和PreDestroy:通過註解指定初始化和銷毀方法定義;
 
1、在測試類TestBean41中添加如下代碼:
 

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. } 
@PostConstruct
public void init() {
    System.out.println("==========init");
}
@PreDestroy
public void destroy() {
    System.out.println("==========destroy");
}
 
2、修改測試方法如下:
 

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. } 
@Test
public void resourceInjectTest1() {
    ((ClassPathXmlApplicationContext) ctx).registerShutdownHook();
    TestBean41 testBean41 = ctx.getBean("testBean41", TestBean41.class);
    Assert.assertEquals("hello", testBean41.getMessage());
}
    類似於通過<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代碼    
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.   
package cn.javass.spring.chapter12.qualifier;
//省略部分import
import javax.inject.Qualifier;
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface JSR330Mysql {
}
 
 
 
2、準備測試Bean:
 
 

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. } 
package cn.javass.spring.chapter12;
import javax.inject.Inject;
import javax.inject.Named;
import javax.sql.DataSource;
import cn.javass.spring.chapter12.qualifier.JSR330Mysql;
public class TestBean51 {
    private DataSource mysqlDataSource;
    private DataSource oracleDataSource;
    @Inject
    public void initDataSoruce(
            @JSR330Mysql  DataSource mysqlDataSource,
            @Named("oracleDataSource") DataSource oracleDataSource) {
        this.mysqlDataSource = mysqlDataSource;
        this.oracleDataSource = oracleDataSource;

    }
  //省略getter 
}
 
3、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

Java代碼    
1. <bean id="testBean51" class="cn.javass.spring.chapter12.TestBean51"/> 
<bean id="testBean51" class="cn.javass.spring.chapter12.TestBean51"/>
 
4、在Spring修改定義的mysqlDataSourceBean數據源:
 

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> 
<bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
         <qualifier value="mysqlDataSource"/>
         <qualifier type="cn.javass.spring.chapter12.qualifier.Mysql"/>
         <qualifier type="cn.javass.spring.chapter12.qualifier.DataSourceType">
             <attribute key="ip" value="localhost"/>
             <attribute key="database" value="MYSQL"/>
         </qualifier>
         <qualifier type="cn.javass.spring.chapter12.qualifier.JSR330Mysql"/>
</bean>
 
 
5、測試方法如下:
 

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. } 
@Test
public void testInject() {
    TestBean51 testBean51 = ctx.getBean("testBean51", TestBean51.class);
    Assert.assertEquals(ctx.getBean("mysqlDataSourceBean"), testBean51.getMysqlDataSource());
    Assert.assertEquals(ctx.getBean("oracleDataSource"), testBean51.getOracleDataSource());
}
 
 
測試也通過瞭,說明JSR-330註解也能很好工作。
 
從測試中可以看出JSR-330註解和Spring自帶註解依賴註入時主要有以下特點:
• Spring自帶的@Autowired的缺省情況等價於JSR-330的@Inject註解;
• Spring自帶的@Qualifier的缺省的根據Bean名字註入情況等價於JSR-330的@Named註解;
• Spring自帶的@Qualifier的擴展@Qualifier限定描述符註解情況等價於JSR-330的@Qualifier註解。
 
 
 
12.2.5  JPA註解
用於註入EntityManagerFactory和EntityManager。
     
1、準備測試Bean:
 

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. } 
package cn.javass.spring.chapter12;
//省略import
public class TestBean61 {
    @PersistenceContext(unitName = "entityManagerFactory")
    private EntityManager entityManager;
  
    @PersistenceUnit(unitName = "entityManagerFactory")
    private EntityManagerFactory entityManagerFactory;
  
    public EntityManager getEntityManager() {
        return entityManager;
    }
    public EntityManagerFactory getEntityManagerFactory() {
        return entityManagerFactory;
    }
}
 
2、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加如下Bean配置:
 

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"/> 
<import resource="classpath:chapter7/applicationContext-resources.xml"/>
<import resource="classpath:chapter8/applicationContext-jpa.xml"/>
<bean id="testBean61" class="cn.javass.spring.chapter12.TestBean61"/>
    此處需要引用第七章和八章的配置文件,細節內容請參考七八兩章。
 
 
3、測試方法如下:
 

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. } 
@Test
public void testJpaInject() {
    TestBean61 testBean61 = ctx.getBean("testBean61", TestBean61.class);
    Assert.assertNotNull(testBean61.getEntityManager());
    Assert.assertNotNull(testBean61.getEntityManagerFactory());
}
    測試也通過瞭,說明JPA註解也能很好工作。
 
JPA註解類似於@Resource註解同樣是先根據unitName屬性去JNDI環境中查找,如果沒找到在到Spring容器中查找。

 

摘自  人生如若初見
 

發佈留言