1. 程式人生 > >Spring Boot2.x-05Spring Boot基礎-使用註解完成依賴注入

Spring Boot2.x-05Spring Boot基礎-使用註解完成依賴注入

概述

xml的方式去描述Bean之間的依賴關係,請參考以前的部落格Spring-bean之間的關係

@Autowired註解

舉個例子: Manager可以安排Engineer去根據Engineer的型別做不同的工作

在這裡插入圖片描述

介面Engineer的介面方法是coding

package com.artisan.springbootmaster.di.intf;

public interface Engineer {

    void coding();
}

假設有個Java程式猿,實現Engineer介面

package com.artisan.springbootmaster.di.intf.
impl; import com.artisan.springbootmaster.di.intf.Engineer; import org.springframework.stereotype.Service; @Service public class JavaEnginerr implements Engineer { @Override public void coding() { System.out.println("Java Engineer works"); } }

我們在實現類JavaEnginerr 上使用@Service註解,使其成為一個受Spring容器管理的bean。

接下來,我們來看下Manager類

package com.artisan.springbootmaster.di;

import com.artisan.springbootmaster.di.intf.Engineer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Manager {

    @Autowired
    Engineer engineer;
public void arrange(){ engineer.coding(); } }

可以通過arrange方法安排engineer工作。 這裡Engineer 通過@Autowired讓IoC容器自動注入進來。

接著我們使用Java類的方式來初始化IoC容器,通過@Configuration標註其是一個配置類 ,通過ComponetScan來掃描基包下面的標註了註解的類,使其成為受Spring IoC容器託管的bean,方便注入

package com.artisan.springbootmaster.di;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "com.artisan.springbootmaster.*")
public class Config {

}

最後,載入Java類的配置,主要是依靠 AnnotationConfigApplicationContext,啟動容器獲取bean,並呼叫對應的方法

package com.artisan.springbootmaster.di;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class DITest {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        Manager manager =  applicationContext.getBean(Manager.class);
        manager.arrange();
    }
}

執行

23:04:08.018 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'manager'
Java Engineer works

@Autowired會根據屬性的型別( by type )找到對應的 Bean 進行注入。 在這裡插入圖片描述

通過結果可以知道,通過註解@Autowired 成功的將JavaEngierr注入到了Manager例項中。

@Autowired的匹配原則

上面這個例子中@Autowired的用法很簡單,我們繼續來看下@Autowired

當然了,Engineer可能有多個,比如又來了個AndroidEngineer

package com.artisan.springbootmaster.di.intf.impl;

import com.artisan.springbootmaster.di.intf.Engineer;
import org.springframework.stereotype.Service;


@Service
public class AndroidEngineer implements Engineer {

    @Override
    public void coding() {
        System.out.println("Android Engineer works");
    }
}

這是IDEA中可以看到,有提示報錯了 在這裡插入圖片描述

讓我們繼續執行下DITest,丟擲了異常

 No qualifying bean of type 'com.artisan.springbootmaster.di.intf.Engineer' available: expected single matching bean but found 2: androidEngineer,javaEnginerr

意思很明顯,@Autowired根據型別來匹配Engineer,卻發現有2個bean都是Engineer型別 ,這下子Spring不知道注入哪個了。

@Autowired的匹配原則:根據型別找到對應的 Bean,如果對應型別的 Bean 不是唯一 的,那麼會繼續根據其屬性名稱和 Bean 的名稱進行匹配。如果匹配上,就會使用該 Bean,如果還無法匹配,就會丟擲異常。

所以根據上面的原則,比較挫的一個辦法(這裡只是說可以這麼改,但是肯定不推薦這麼改

既然是兩個,那我就讓bean的名字一樣唄

  • 方法一:Manager中的Engineer engineer保持不變,給這兩個Engineer中的任意一個標註@Service(value "engineer"),指定其bean的名字為engineer,這樣根據name就匹配上了,同樣不會丟擲異常。測試通過。
  • 方法二:Manager中的Engineer engineer改為這兩個bean的任意一個名字,@Service標註的實現類Bean的名字為預設第一個字母小寫其餘保持不變,這樣name也能匹配上,同樣不會丟擲異常。測試通過。

在這裡插入圖片描述

結果 在這裡插入圖片描述

這裡只是舉例驗證下Spring @Autowired的匹配規則,實際工作中並不推薦這麼改。。。。

@Autowired的 required 屬性

@Autowired 是一個預設必須找到對應 Bean 的註解,如果不能確定其標註屬性一定會存在並且允許這個被標註的屬性為 null , 那麼你可以配置@Autowired 屬性 required 為 false.

@Autowired既可以標註在屬性上,也可以標註在方法上

 @Autowired(required = false)

使用@Primary 和@Qualifier消除@Autowired的歧義

上面通過修改name,使其name保持一致的方式消除了歧義,可以正常的注入,不過並不推薦。

@Primary 不推薦使用

也可以使用@Primary,當然了,也不推薦這麼幹。 因為另外一個類也可以標註@Primary,Spring又無法知道注入哪個了。

註解@Primary是修改優先權的註解,像上面的兩個例子,有2個beanandroidEngineer,javaEnginerr, 如果我們僅在JavaEnginerr這個類上標註@Primary,意思是告訴Spring IoC 容器 , 當發現有多個同樣型別的 Bean ,請優先使用標註了@Primary的這個bean進行注入。

在這裡插入圖片描述

結果: 在這裡插入圖片描述

@Qualifier推薦使用

@Qualifier的value屬性定義bean的名,該名稱將會和@Autowired 組合在一起,通過型別和名稱一起找到 Bean。Spring IoC容器中Bean 名稱是唯一的標識,通過這個就可以消除歧義性了

在這裡插入圖片描述

結果

在這裡插入圖片描述

即使 JavaEnginerr標註了@Primary,但是由於使用了@Qualifier,注入的依然是androidEngineer.

在建構函式中使用@Autowired

上面的例子,我們是在屬性【也可以是方法】上使用的@Autowired. 如果使建構函式呢?

我們改造下Manager

package com.artisan.springbootmaster.di;

import com.artisan.springbootmaster.di.intf.Engineer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class Manager {

    Engineer engineer;

    public void arrange(){
        engineer.coding();
    }


    public Manager(@Autowired @Qualifier("javaEnginerr") Engineer engineer){
        this.engineer = engineer;
    }
}

  • 取消標註在屬性上的註解
  • 在建構函式上增加註解,使用方法一樣。
  • 如果僅有一個型別的Bean, @Qualifier就沒有必要加上了。

執行

在這裡插入圖片描述