三、@Qualifier:限定描述符,用於細粒度選擇候選者;
@Autowired默認是根據類型進行注入的,因此如果有多個類型一樣的Bean候選者,則需要限定其中一個候選者,否則將拋出異常
@Qualifier限定描述符除了能根據名字進行注入,更能進行更細粒度的控制如何選擇候選者,具體使用方式如下:
@Qualifier(value = "限定標識符")
字段、方法、參數
(1)、根據基於XML配置中的<qualifier>標籤指定的名字進行注入,使用如下方式指定名稱:
<qualifier type="org.springframework.beans.factory.annotation.Qualifier" value="限定標識符"/>
其中type屬性可選,指定類型,默認就是Qualifier註解類,name就是給Bean候選者指定限定標識符,一個Bean定義中只允許指定類型不同的<qualifier>,如果有多個相同type後面指定的將覆蓋前面的。
1、準備測試Bean:
DataSource.java
package com.bean;
public interface DataSource {
public void connection();
}
MysqlDriveManagerDataSource.java
package com.bean;
public class MysqlDriveManagerDataSource implements DataSource{
public void connection() {
System.out.println("mysql database connecting...");
}
}
OracleDriveManagerDataSource.java
package com.bean;
public class OracleDriveManagerDataSource implements DataSource{
public void connection() {
System.out.println("oracle database connecting...");
}
}
TestBean.java
package com.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class TestBean {
private DataSource dataSource;
@Autowired
public void initDataSource(@Qualifier("oracleDataSource") DataSource dataSource){
this.dataSource = dataSource;
}
public DataSource getDataSource() {
return dataSource;
}
}
其中TestBean.java中使用 @Qualifier還有一種方式
@Autowired
@Qualifier(value="oracleDataSource")
public void initDataSource(DataSource dataSource){
this.dataSource = dataSource;
}
2、在Spring配置文件 添加如下Bean配置:
<bean id="testBean" class="com.bean.TestBean"/>
我們使用@Qualifier("oracleDataSource")來指定候選Bean的限定標識符,我們需要在配置文件中使用<qualifier>標籤來指定候選Bean的限定標識符“oracleDataSource”:
<bean id="mysqlDataSourceBean" class="com.bean.MysqlDriveManagerDataSource">
<qualifier value="mysqlDataSource"/>
</bean>
<bean id="oracleDataSourceBean" class="com.bean.OracleDriveManagerDataSource">
<qualifier value="oracleDataSource"/>
</bean>
3、測試方法如下:
@Test
public void autowiredTest(){
TestBean bean = ctx.getBean("testBean", TestBean.class);
DataSource dataSource = bean.getDataSource();
if(dataSource instanceof MysqlDriveManagerDataSource){
System.out.println("mysql");
}else if(dataSource instanceof OracleDriveManagerDataSource){
System.out.println("oracle");
}
dataSource.connection();
try{
ctx.getBean("mysqlDataSource");
}catch(Exception e){
if(e instanceof NoSuchBeanDefinitionException){
System.out.println("@Qualifier不能作爲Bean的標識符");
}
e.printStackTrace();
}
}
從測試可以看出使用<qualifier>標籤指定的限定標識符只能被@Qualifier使用,不能作爲Bean的標識符,如“ctx.getBean("mysqlDataSource")”是獲取不到Bean的。
(2)、缺省的根據Bean名字注入:最基本方式,是在Bean上沒有指定<qualifier>標籤時一種容錯機制,即缺省情況下使用Bean標識符注入,但如果你指定了<qualifier>標籤將不會發生容錯。
1、準備測試Bean:
package com.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class TestBean {
private DataSource dataSource;
@Autowired
@Qualifier(value="mysqlDataSourceBean")
public void initDataSource(DataSource dataSource){
this.dataSource = dataSource;
}
public DataSource getDataSource() {
return dataSource;
}
}
2、在Spring配置文件
添加如下Bean配置:
<bean id="mysqlDataSourceBean" class="com.bean.MysqlDriveManagerDataSource"/>
<bean id="oracleDataSourceBean" class="com.bean.OracleDriveManagerDataSource"/>
3、測試方法如下:
@Test
public void autowiredTest(){
TestBean bean = ctx.getBean("testBean", TestBean.class);
DataSource dataSource = bean.getDataSource();
if(dataSource instanceof MysqlDriveManagerDataSource){
System.out.println("mysql");
}else if(dataSource instanceof OracleDriveManagerDataSource){
System.out.println("oracle");
}
dataSource.connection();
}
因爲配置文件中並沒有使用 @Qualifier標籤
所以我們在bean中注入的時候是注入 bean
@Qualifier(value="mysqlDataSourceBean")
(3)、擴展@Qualifier限定描述符註解(不帶參數):對@Qualifier的擴展來提供細粒度選擇候選者;
具體使用方式就是自定義一個註解並使用@Qualifier註解其即可使用。
首先讓我們考慮這樣一個問題,如果我們有兩個數據源,分別爲Mysql和Oracle,因此注入兩者相關資源時就牽扯到數據庫相關,如在DAO層注入SessionFactory時,當然可以採用前邊介紹的方式,但爲了簡單和直觀我們希望採用自定義註解方式。
1、擴展@Qualifier限定描述符註解來分別表示Mysql和Oracle數據源
package com.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Mysql {
}
package com.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Oracle {
}
2、準備測試Bean:
package com.bean;
import org.springframework.beans.factory.annotation.Autowired;
import com.annotation.Mysql;
import com.annotation.Oracle;
public class TestBean {
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配置文件 添加如下Bean配置:
<bean id="testBean" class="com.bean.TestBean"/>
4、在Spring修改定義的兩個數據源:
<bean id="mysqlDataSourceBean" class="com.bean.MysqlDriveManagerDataSource">
<qualifier value="mysqlDataSource"/>
<qualifier type="com.annotation.Mysql"/>
</bean>
<bean id="oracleDataSourceBean" class="com.bean.OracleDriveManagerDataSource">
<qualifier value="oracleDataSource"/>
<qualifier type="com.annotation.Oracle"/>
</bean>
5、測試方法如下:
@Test
public void autowiredTest(){
TestBean bean = ctx.getBean("testBean", TestBean.class);
DataSource dataSource = bean.getMysqlDataSource();
if(dataSource instanceof MysqlDriveManagerDataSource){
System.out.println("mysql");
}else if(dataSource instanceof OracleDriveManagerDataSource){
System.out.println("oracle");
}
dataSource.connection();
}
測試也通過了,說明我們擴展的@Qualifier限定描述符註解也能很好工作。
(3)、擴展@Qualifier限定描述符註解(帶參數):對@Qualifier的擴展來提供細粒度選擇候選者;
前邊演示了不帶屬性的註解,接下來演示一下帶參數的註解:
1、首先定義數據庫類型:
package com.enumBean;
public enum DataBase {
ORACLE,MYSQL;
}
2、其次擴展@Qualifier限定描述符註解
package com.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
import com.enumBean.DataBase;
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface DataSourceType {
String ip(); //指定ip,用於多數據源情況
DataBase database(); //指定數據庫類型
}
3、準備測試Bean:
package com.bean;
import org.springframework.beans.factory.annotation.Autowired;
import com.annotation.DataSourceType;
import com.enumBean.DataBase;
public class TestBean {
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;
}
public DataSource getMysqlDataSource() {
return mysqlDataSource;
}
public DataSource getOracleDataSource() {
return oracleDataSource;
}
}
4、在Spring配置文件
添加如下Bean配置:
<bean id="testBean" class="com.bean.TestBean"/>
5、在Spring修改定義的兩個數據源:
<bean id="mysqlDataSourceBean" class="com.bean.MysqlDriveManagerDataSource">
<qualifier value="mysqlDataSource"/>
<qualifier type="com.annotation.DataSourceType">
<attribute key="ip" value="localhost"/>
<attribute key="database" value="MYSQL"/>
</qualifier>
</bean>
<bean id="oracleDataSourceBean" class="com.bean.OracleDriveManagerDataSource">
<qualifier value="oracleDataSource"/>
<qualifier type="com.annotation.DataSourceType">
<attribute key="ip" value="localhost"/>
<attribute key="database" value="ORACLE"/>
</qualifier>
</bean>
6、測試方法如下:
@Test
public void autowiredTest(){
TestBean bean = ctx.getBean("testBean", TestBean.class);
DataSource dataSource = bean.getMysqlDataSource();
if(dataSource instanceof MysqlDriveManagerDataSource){
System.out.println("mysql");
}else if(dataSource instanceof OracleDriveManagerDataSource){
System.out.println("oracle");
}
dataSource.connection();
}