# 【第十二章】零配置 之 12.2 注解實現Bean依賴注入 ——跟我學spring3
## 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容器中開啟注解驅動支持,即使用如下配置方式開啟:
```
<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注入,可以使用如下方式來指定:
```
@Requried
setter方法
```
1、準備測試Bean
```
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配置:
```
<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、測試類和測試方法如下:
```
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容器啟動時將拋出如下異常:
```
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的自動裝配,默認是根據類型注入,可以用于構造器、字段、方法注入,使用方式如下:
```
@Autowired(required=true)
構造器、字段、方法
```
@Autowired默認是根據參數類型進行自動裝配,且必須有一個Bean候選者注入,如果允許出現0個Bean候選者需要設置屬性“required=false”,“required”屬性含義和@Required一樣,只是@Required只適用于基于XML配置的setter注入方式。
**(1)、構造器注入:**通過將@Autowired注解放在構造器上來完成構造器注入,默認構造器參數通過類型自動裝配,如下所示:
1、準備測試Bean,在構造器上添加@AutoWired注解:
```
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配置:
```
<bean id="testBean11" class="cn.javass.spring.chapter12.TestBean11"/>
```
3、測試類如下:
```
@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注解:
```
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配置:
```
<bean id="testBean12" class="cn.javass.spring.chapter12.TestBean12"/>
```
3、測試方法如下:
```
@Test
public void testAutowiredForField() {
TestBean12 testBean12 = ctx.getBean("testBean12", TestBean12.class);
Assert.assertEquals("hello", testBean12.getMessage());
}
```
字段注入在基于XML配置中無相應概念,字段注入不支持靜態類型字段的注入。
**(3)、方法參數注入:**通過將@Autowired注解放在方法上來完成方法參數注入。
1、準備測試Bean,在方法上添加@AutoWired注解:
```
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;
}
}
```
```
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配置:
```
<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、測試方法如下:
```
@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表達式,可以放置在字段方法或參數上,使用方式如下:
```
@Value(value = "SpEL表達式")
字段、方法、參數
```
1、可以在類字段上使用該注解:
```
@Value(value = "#{message}")
private String message;
```
2、可以放置在帶@Autowired注解的方法的參數上:
```
@Autowired
public void initMessage(@Value(value = "#{message}#{message}") String message) {
this.message = message;
}
```
3、還可以放置在帶@Autowired注解的構造器的參數上:
```
@Autowired
private TestBean43(@Value(value = "#{message}#{message}") String message) {
this.message = message;
}
```
具體測試詳見DependencyInjectWithAnnotationTest 類的testValueInject測試方法。
**四、@Qualifier:限定描述符,用于細粒度選擇候選者;**
@Autowired默認是根據類型進行注入的,因此如果有多個類型一樣的Bean候選者,則需要限定其中一個候選者,否則將拋出異常,詳見【3.3.3? 自動裝配】中的根據類型進行注入;
@Qualifier限定描述符除了能根據名字進行注入,但能進行更細粒度的控制如何選擇候選者,具體使用方式如下:
```
@Qualifier(value = "限定標識符")
字段、方法、參數
```
**(1)、根據基于XML配置中的<qualifier>標簽指定的名字進行注入,使用如下方式指定名稱:**
```
<qualifier type="org.springframework.beans.factory.annotation.Qualifier" value="限定標識符"/>
```
其中type屬性可選,指定類型,默認就是Qualifier注解類,name就是給Bean候選者指定限定標識符,一個Bean定義中只允許指定類型不同的<qualifier>,如果有多個相同type后面指定的將覆蓋前面的。
1、準備測試Bean:
```
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配置:
```
<bean id="testBean31" class="cn.javass.spring.chapter12.TestBean31"/>
```
我們使用@Qualifier("mysqlDataSource")來指定候選Bean的限定標識符,我們需要在配置文件中使用<qualifier>標簽來指定候選Bean的限定標識符“mysqlDataSource”:
```
<bean id="mysqlDataSourceBean" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<qualifier value="mysqlDataSource"/>
</bean>
```
3、測試方法如下:
```
@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:
```
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配置:
```
<bean id="testBean32" class="cn.javass.spring.chapter12.TestBean32"/>
<bean id="oracleDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
```
3、測試方法如下:
```
@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數據源
```
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 {
}
```
```
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:
```
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配置:
```
<bean id="testBean33" class="cn.javass.spring.chapter12.TestBean33"/>
```
4、在Spring修改定義的兩個數據源:
```
<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、測試方法如下:
```
@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、首先定義數據庫類型:
```
package cn.javass.spring.chapter12.qualifier;
public enum DataBase {
ORACLE, MYSQL;
}
```
2、其次擴展@Qualifier限定描述符注解
```
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:
```
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配置:
```
<bean id="testBean34" class="cn.javass.spring.chapter12.TestBean34"/>
```
5、在Spring修改定義的兩個數據源:
```
<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、測試方法如下:
```
@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、首先使用如下方式定義一個自定義注解限定描述符:
```
package cn.javass.spring.chapter12.qualifier;
//省略import
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomQualifier {
String value();
}
```
2、準備測試Bean:
```
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配置:
```
<bean id="testBean35" class="cn.javass.spring.chapter12.TestBean35"/>
```
4、然后在Spring配置文件中注冊CustomQualifier自定義注解限定描述符,只有注冊了Spring才能識別:
```
<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、測試方法如下:
```
@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屬性將根據名字裝配,可以使用如下方式來指定:
```
@Resource(name = "標識符")
字段或setter方法
```
1、準備測試Bean:
```
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配置:
```
<bean id="testBean41" class="cn.javass.spring.chapter12.TestBean41"/>
```
3、測試方法如下:?
```
@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中添加如下代碼:
```
@PostConstruct
public void init() {
System.out.println("==========init");
}
@PreDestroy
public void destroy() {
System.out.println("==========destroy");
}
```
2、修改測試方法如下:
```
@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數據源
```
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:
```
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配置:
```
<bean id="testBean51" class="cn.javass.spring.chapter12.TestBean51"/>
```
4、在Spring修改定義的mysqlDataSourceBean數據源:
```
<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、測試方法如下:
```
@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:
```
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配置:
```
<import resource="classpath:chapter7/applicationContext-resources.xml"/>
<import resource="classpath:chapter8/applicationContext-jpa.xml"/>
<bean id="testBean61" class="cn.javass.spring.chapter12.TestBean61"/>
```
此處需要引用第七章和八章的配置文件,細節內容請參考七八兩章。
3、測試方法如下:
```
@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容器中查找。
原創內容,轉載請注明私塾在線【[http://sishuok.com/forum/blogPost/list/0/2545.html](http://sishuok.com/forum/blogPost/list/0/2545.html#7319)】
- 跟我學 Spring3
- 【第二章】 IoC 之 2.1 IoC基礎 ——跟我學Spring3
- 【第二章】 IoC 之 2.2 IoC 容器基本原理 ——跟我學Spring3
- 【第二章】 IoC 之 2.3 IoC的配置使用——跟我學Spring3
- 【第三章】 DI 之 3.1 DI的配置使用 ——跟我學spring3
- 【第三章】 DI 之 3.2 循環依賴 ——跟我學spring3
- 【第三章】 DI 之 3.3 更多DI的知識 ——跟我學spring3
- 【第三章】 DI 之 3.4 Bean的作用域 ——跟我學spring3
- 【第四章】 資源 之 4.1 基礎知識 ——跟我學spring3
- 【第四章】 資源 之 4.2 內置Resource實現 ——跟我學spring3
- 【第四章】 資源 之 4.3 訪問Resource ——跟我學spring3
- 【第四章】 資源 之 4.4 Resource通配符路徑 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.1 概述 5.2 SpEL基礎 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.3 SpEL語法 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.4在Bean定義中使用EL—跟我學spring3
- 【第六章】 AOP 之 6.1 AOP基礎 ——跟我學spring3
- 【第六章】 AOP 之 6.2 AOP的HelloWorld ——跟我學spring3
- 【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.5 AspectJ切入點語法詳解 ——跟我學spring3
- 【第六章】 AOP 之 6.6 通知參數 ——跟我學spring3
- 【第六章】 AOP 之 6.7 通知順序 ——跟我學spring3
- 【第六章】 AOP 之 6.8 切面實例化模型 ——跟我學spring3
- 【第六章】 AOP 之 6.9 代理機制 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.1 概述 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.2 JDBC模板類 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.3 關系數據庫操作對象化 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.4 Spring提供的其它幫助 ——跟我學spring3【私塾在線原創】
- 【第七章】 對JDBC的支持 之 7.5 集成Spring JDBC及最佳實踐 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.1 概述 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.2 集成Hibernate3 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.3 集成iBATIS ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.4 集成JPA ——跟我學spring3
- 【第九章】 Spring的事務 之 9.1 數據庫事務概述 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.2 事務管理器 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.3 編程式事務 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.4 聲明式事務 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.1 概述 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.2 集成Struts1.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.3 集成Struts2.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.4 集成JSF ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.1 概述 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.2 實現通用層 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.3 實現積分商城層 ——跟我學spring3
- 【第十二章】零配置 之 12.1 概述 ——跟我學spring3
- 【第十二章】零配置 之 12.2 注解實現Bean依賴注入 ——跟我學spring3
- 【第十二章】零配置 之 12.3 注解實現Bean定義 ——跟我學spring3
- 【第十二章】零配置 之 12.4 基于Java類定義Bean配置元數據 ——跟我學spring3
- 【第十二章】零配置 之 12.5 綜合示例-積分商城 ——跟我學spring3
- 【第十三章】 測試 之 13.1 概述 13.2 單元測試 ——跟我學spring3
- 【第十三章】 測試 之 13.3 集成測試 ——跟我學spring3
- 跟我學 Spring MVC
- SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常見問題總結
- Spring Web MVC中的頁面緩存支持 ——跟我學SpringMVC系列
- Spring3 Web MVC下的數據類型轉換(第一篇)——《跟我學Spring3 Web MVC》搶先看
- Spring3 Web MVC下的數據格式化(第二篇)——《跟我學Spring3 Web MVC》搶先看
- 第一章 Web MVC簡介 —— 跟開濤學SpringMVC
- 第二章 Spring MVC入門 —— 跟開濤學SpringMVC
- 第三章 DispatcherServlet詳解 ——跟開濤學SpringMVC
- 第四章 Controller接口控制器詳解(1)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(2)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(3)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解 (4)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(5)——跟著開濤學SpringMVC
- 跟著開濤學SpringMVC 第一章源代碼下載
- 第二章 Spring MVC入門 源代碼下載
- 第四章 Controller接口控制器詳解 源代碼下載
- 第四章 Controller接口控制器詳解(6)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(7 完)——跟著開濤學SpringMVC
- 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 源代碼下載 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 注解式控制器運行流程及處理器定義 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- 源代碼下載 第六章 注解式控制器詳解
- SpringMVC3強大的請求映射規則詳解 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- Spring MVC 3.1新特性 生產者、消費者請求限定 —— 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(1)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(2)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC數據類型轉換——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據格式化——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據驗證——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC