1. 程式人生 > >Spring整理系列(10)——@Autowired自動裝配、結合@Qualifier過濾及與

Spring整理系列(10)——@Autowired自動裝配、結合@Qualifier過濾及與 阿新 發佈:2019-01-08

一、使用@Autowired註解,實現自動裝配

在使用註解裝配之前,首先要開啟註解裝配的方式,那就是在配置檔案中加上下面這句話<context:annotation-config></context:annotation-config>,也可以使用<context:component-scan>標籤(兩者的區別在Spring整理系列(01)——spring概念簡介、bean掃描與註冊實現方式中有提到)。

使用@Autowired註解,可以用在屬性、setter方法、constructor構造方法上,實現自動裝配。

spring的xml配置檔案:

    <!-- 開啟註解配置 -->
<context:annotation-config></context:annotation-config> <!-- 註冊bean --> <bean id="userDao" class="com.jsun.test.springDemo.ioc.User.UserDaoImpl"></bean> <!-- 註冊bean --> <bean id="userService" class="com.jsun.test.springDemo.ioc.User.UserServiceImpl"
>
</bean>

UserServiceImpl:

1、註解在setter方法上:

    private UserDao userDao;

    //添加註解,匹配注入與引數型別有關,即byType,與引數名稱、setter方法名稱、成員變數屬性名稱無關
    @Autowired
    public void setUserDao(UserDao userDao) {
        System.out.println("註解自動裝配setUserDao注入");
        this.userDao = userDao;
    }

2、constructor構造方法上:

    private UserDao userDao;

    //添加註解,匹配注入與引數型別有關,即byType,與引數名稱、成員變數屬性名稱無關
    @Autowired
    public UserServiceImpl(UserDao userDao){
        System.out.println("註解自動裝配構造器UserServiceImpl注入");
        this.userDao = userDao;
    }

3、宣告的屬性上:

    //添加註解,先按照屬性名稱匹配注入,如果未找到則按照屬性型別匹配注入,即byName-->byType
    @Autowired
    private UserDao userDao;

二、使用@Autowired丟擲異常情況及與@Qualifier註解結合使用情況


丟擲異常情況:
@Autowired使用的時候必須只有一個Bean適合裝配,否則spring會丟擲異常;

1、NoSuchBeanDefinitionException異常:如果在應用上下文當中找不到相應的bean去自動裝配,那麼spring也會丟擲異常。

。。。
Caused by: org.springframework.beans.factory.BeanCreationException:  。。。
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type。。。

要避免這種情況發生,而且需要裝配的屬性也不是必須要裝配的話,可以使用@Autowired(required=false)註解:

    //在注入bean的時候該屬性不是必須的,即使找不到對應bean注入,也不會報異常
    @Autowired(required=false)
    private UserDao userDao;

2、NoUniqueBeanDefinitionException異常:如果在同一個spring容器中出現了兩個或多個都必須存在的bean,然而自動裝配只需要裝配期中一個,也會丟擲異常。

父類介面:

public interface TestBeanInterface {
    public void sayHello();
}

兩個實現子類:

@Component("testBean1")
public class TestBean1 implements TestBeanInterface{
    public void sayHello(){
        System.out.println("TestBean1 sayHello...");
    }
}

@Component("testBean2")
public class TestBean2 implements TestBeanInterface{
    public void sayHello(){
        System.out.println("TestBean2 sayHello...");
    }
}

測試類中:

    //以介面父類宣告的成員變數屬性,在spring容器中有它兩個子類的bean
    private TestBeanInterface testBean;

    //自動裝配,按照引數型別匹配注入bean,此時spring容器中TestBeanInterface型別有兩個bean
    @Autowired
    public void setTestBean(TestBeanInterface t){
        this.testBean = t;
    }

執行測試的異常:

。。。
Caused by: org.springframework.beans.factory.BeanCreationException:。。。
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException:。。。

這個時候@Autowired可以結合使用@Qualifier註解指定一個Bean來裝配:

    @Autowired
    public void setTestBean(@Qualifier("testBean2")TestBeanInterface t){
        this.testBean = t;
    }


注:@Qualifier註解其實就是先按照bean的name過濾裝配指定型別bean,把@Autowired放在成員變數屬性上,也是先按照屬性name查詢,再按型別注入,所以把@Autowired放在成員變數屬性上報NoUniqueBeanDefinitionException異常的概率比較低,並且不需要setter或構造器,推薦使用。



三、@Autowired可以裝配的spring內部bean,不可以裝配的bean

1、@Autowired可以註解的spring內部型別:

可以用@Autowired註解那些解析依賴性介面,比如BeanFactory、ApplicationContext、Environment、ResourceLoader、ApplicationEventPublisher、MessageSource等

    @Autowired
    private ApplicationContext context;

    @Test
    public void testGetBean(){
        TestBeanInterface tb = (TestBeanInterface)context.getBean("testBean1");
        System.out.println(tb.getClass().getName());
    }

2、@Autowired不可以註解的型別:

因為@Autowired是由Spring BeanPostProcessor處理的,所以不能在自己的BeanPostProcessor或BeanFactoryPostProcessor型別應用@Autowired註解,這些型別必須通過xml或者@Bean註解形式載入。

四、@Autowired與JSR-250提供的@Resource註解的區別

1、先說@Autowired註解:

@Autowired是Spring提供的註解,需匯入Package:org.springframework.beans.factory.annotation.Autowired;

@Autowired用在setter和構造器上只按照byType注入,用在成員變數field上,先按照byName注入,找不到則按照byType注入;

結合@Qualifier註解,可讓setter和構造器實現byName匹配注入。



2、再說@Resource註解:

@Resource由J2EE提供,需匯入javax.annotation.Resource;

@Resource有兩個中重要的屬性:name和type ,Spring將name屬性解析為bean的名字,type屬性解析為bean的型別。所以如果使用name屬性,則按照byName自動注入,使用type屬性則按照byType自動注入。如果既不指定name也不指定type屬性,這時將通過反射機制預設使用byName自動注入。@Resource自動裝配注入順序如下:

  (1). 如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則丟擲異常;
  (2). 如果指定了name,則從上下文中查詢名稱(id)匹配的bean進行裝配,找不到則丟擲異常;
  (3). 如果指定了type,則從上下文中找到型別匹配的唯一bean進行裝配,找不到或者找到多個,都會丟擲異常;
  (4). 如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;如果沒有匹配,則回退為一個原始型別進行匹配,如果匹配則自動裝配。


@Resource分別可以用在field、setter上,無法應用在constructor構造器上

//用於field欄位
@Resource
private TestBeanInterface testBean;

//用於setter
@Resource(name = "testBean1")
public void setTestBean(TestBeanInterface t){
    this.testBean = t;
}


注:@Resource放在setter方法上,setter方法的引數必須是一個引數,如果是多引數,則丟擲如下異常:

...
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ...
...
Caused by: java.lang.IllegalStateException: @Resource annotation requires a single-arg method:...


如果需要多引數setter或者構造器注入,還需要替換為@Autowired結合@Qualifier實現。



3、補充:集合或Map型別bean,無法通過@Autowired註解注入,因為沒有型別匹配到這樣的bean,必須通過@Resource註解注入,通過唯一名稱引用集合或Map型別bean

五、JSR-330註解@Inject、@Name使用介紹

1、spring3.0開始支援JSR330標註註解,使用JSR330需要引入javax.inject包,使用maven引入:

    <!-- 引入對JSR330的註解支援包 -->
    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>

2、@Inject:
等效於@Autowired,可以用於成員變數屬性、setter方法、構造器,包括匹配注入情況和丟擲異常情況,可以互換使用,程式碼例項參照上面@Autowired註解。

3、@Named:
如果想使用特定名稱進行依賴注入,可以使用@Named,此時與@Quarlifier註解作用相同。

    @Inject
    private UserDao userDao1;

    @Autowired
    @Named("userDao2")
    private UserDao userDao2;

    @Inject
    @Named("userDao2")
    public void setUserDao2(UserDao ud2){
        this.userDao2 = ud2;
    }
    @Inject
    public UserServiceImpl(@Named("userDao1")UserDao ud1){
        this.userDao1 = ud1;
    }

用在類上,與@Component註解作用是等效的。

@Named("tb")
public class TestBean {

    @PostConstruct
    public void start(){
        System.out.println("TestBean 初始化。。。");
    }

    @PreDestroy
    public void cleanUp(){
        System.out.println("TestBean 銷燬。。。");
    }
}