快手一面:Spring @Qualifier 能解決 Bean 沖突嗎?
這篇文章,我們將深度分析一道快手的面試題: Spring 的@Qualifier注解能解決 Bean沖突嗎?

一、功能概要
@Qualifier注解是 Spring中用于在依賴注入時(shí)明確指定要注入的 Bean 的工具,特別是在容器中存在多個(gè)相同類型的 Bean 時(shí)。它幫助開發(fā)者解決由于 Bean 名稱沖突或多重實(shí)現(xiàn)導(dǎo)致的歧義問題,從而確保注入正確的 Bean 實(shí)例。
比如:當(dāng)容器中存在多個(gè)同類型的 Bean 時(shí),Spring 無法確定應(yīng)該注入哪一個(gè) Bean,這時(shí) @Qualifier 就派上用場了。它通過指定 Bean 的名稱或自定義限定符來告知 Spring 具體應(yīng)該注入哪個(gè) Bean。
@Qualifier 注解的源碼如下圖:

通過源碼,我們可以看出,@Qualifier 只能用于字段或參數(shù)。接下來,我們將從三個(gè)角度來分析@Qualifier的使用。
二、使用方法
1. 按 Bean 名稱指定
@Qualifier 通常與 @Autowired 一起使用,通過指定 Bean 的名稱來選擇具體的實(shí)現(xiàn),如下代碼示例:
@Autowired
@Qualifier("ServiceImpl2")
private Service Service;確保 @Qualifier 中的名稱與目標(biāo) Bean 的名稱(默認(rèn)是類名首字母小寫,或者通過 @Component("customName") 指定的名稱)相匹配。
2. 在構(gòu)造函數(shù)中使用
對(duì)于構(gòu)造函數(shù)注入,也可以使用 @Qualifier,如下代碼示例:
@Component
publicclass Controller {
    privatefinal Service Service;
    @Autowired
    public Controller(@Qualifier("ServiceImpl2") Service Service) {
        this.Service = Service;
    }
    public void execute() {
        Service.performService();
    }
}3. 結(jié)合自定義限定符
我們還可以創(chuàng)建自定義的限定符注解,以提高代碼的可讀性和可維護(hù)性,如下代碼示例:
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface ServiceType {}然后在 Bean 和注入點(diǎn)使用這個(gè)自定義注解:
@Component
@ServiceType
public class ServiceImpl implements Service {
    // 實(shí)現(xiàn)細(xì)節(jié)
}
@Autowired
@ServiceType
private Service Service;三、示例分析
為了更好地理解 @Qualifier 的用法,這里以一個(gè)接口 Service 以及兩個(gè)實(shí)現(xiàn)類 ServiceImpl1 和 ServiceImpl2的使用為例,如下代碼示例:
public interface Service {
    void performService();
}
@Component
publicclass ServiceImpl1 implements Service {
    @Override
    public void performService() {
        System.out.println("Service Implementation 1");
    }
}
@Component
publicclass ServiceImpl2 implements Service {
    @Override
    public void performService() {
        System.out.println("Service Implementation 2");
    }
}如果我們想在另一個(gè)組件中嘗試注入 Service:
@Component
public class Controller {
    @Autowired
    private Service Service;
    public void execute() {
        Service.performService();
    }
}此時(shí),Spring 會(huì)拋出以下異常,因?yàn)榇嬖诙鄠€(gè) Service 的實(shí)現(xiàn):
NoUniqueBeanDefinitionException: No qualifying bean of type 'com.yuanjava.Service' available: expected single bean, but found 2因此,我們可以通過使用 @Qualifier,明確指定要注入的 Bean,如下代碼示例:
@Component
public class Controller {
    @Autowired
    @Qualifier("ServiceImpl1")
    private Service Service;
    public void execute() {
        Service.performService();
    }
}這樣,Spring 就會(huì)直接注入 ServiceImpl1,避免了歧義。到此,Bean 沖突問題就完美解決。
四、與 @Primary 的區(qū)別
在分析完 @Qualifier注解后,我們?cè)俜治鲆幌潞退粯?,可以影?Bean優(yōu)先級(jí)的 @Primary注解,該注解用于標(biāo)記一個(gè) Bean 為首選 Bean,當(dāng)存在多個(gè)相同類型的 Bean 時(shí),Spring 會(huì)默認(rèn)注入標(biāo)記了 @Primary 的 Bean,除非另有指定(如使用 @Qualifier)。
@Component
@Primary
public class PrimaryService implements Service {
    // 實(shí)現(xiàn)
}
@Component
public class SecondaryService implements Service {
    // 實(shí)現(xiàn)
}
@Autowired
private Service Service; // 注入 PrimaryService如果我們想注入 SecondaryService,可以使用 @Qualifier:
@Autowired
@Qualifier("secondaryService")
private Service Service; // 注入 SecondaryService五、總結(jié)
本文,我們分析了 @Qualifier的工作原理。@Qualifier 是 Spring 中用于解決 Bean 沖突的有力工具,尤其在多實(shí)現(xiàn)類的場景下。通過明確指定要注入的 Bean,@Qualifier 確保了依賴注入的準(zhǔn)確性和可維護(hù)性。結(jié)合 @Primary、自定義限定符等,開發(fā)者可以靈活地管理和注入所需的 Bean 實(shí)例,從而構(gòu)建更清晰、可管理的應(yīng)用結(jié)構(gòu)。















 
 
 














 
 
 
 