最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring之@Qualifier注解的具體使用

 更新時間:2024年08月18日 08:43:52   作者:一只懶魚a  
本文主要介紹了Spring之@Qualifier注解的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1. 前言

當(dāng)我們注入的依賴存在多個候選者,我們得使用一些方法來篩選出唯一候選者,否則就會拋出異常

2. demo 演示

2.1 創(chuàng)建接口 Car,以及兩個實現(xiàn)其接口的子類

public interface Car {
}

@Component
public class RedCar implements Car {
}

@Component
public class WhiteCar implements Car {
}

2.2 創(chuàng)建實體類 Person

@Component
public class Person {

    @Autowired
    private Car car;
}

2.3 創(chuàng)建配置類以及 Main 類

@ComponentScan("com.test.qualifier")
public class AppConfig {

}

public class Main {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        Person bean = context.getBean(Person.class);
        System.out.println(bean);

    }
}

2.4 運行main方法

啟動過程,拋出異常

2.5 解決方法

  • 在 WhiteCar 或者 RedCar 所在的類上加 @Primary 注解
  • 將 private Car car 改成 private Car redCar
  • 使用 @Qualifier 注解

3. @Qualifier 注解源碼

 從源碼中我們知道這個注解可以作用于屬性、方法、參數(shù)、類、注解上面

3.1 作用于屬性上

我們以 demo 演示代碼為前提,使用 @Qualifier 注解

3.1.1 改造 Person 類

@Component
public class Person {

    @Autowired
    @Qualifier("redCar")
    private Car car;

}

 3.1.2 運行main方法,查看運行結(jié)果

3.2 作用于方法上

3.2.1 創(chuàng)建一個接口 Animal,以及兩個實現(xiàn)類

public interface Animal {
}

public class Dog implements Animal {
}

public class Cat implements Animal {
}

3.2.2 創(chuàng)建配置類

@Configuration
public class AnimalConfig {

    @Bean
    @Qualifier("mimi")
    public Cat cat(){
        return new Cat();
    }

    @Bean
    @Qualifier("wangcai")
    public Dog dog(){
        return new Dog();
    }
}

3.2.3 改造 Person 類

@Component
public class Person {

    @Autowired
    @Qualifier("redCar")
    private Car car;

    @Autowired
    @Qualifier("mimi")
    private Animal animal;

}

3.2.4 運行main方法,查看運行結(jié)果

3.3 作用于類上

3.3.1 改造 Person 和 RedCar

@Component
@Qualifier("car666")
public class RedCar implements Car {
}

@Component
public class Person {

    @Autowired
    @Qualifier("car666")
    private Car car;

    @Autowired
    @Qualifier("mimi")
    private Animal animal;

}

3.3.2 運行 main 方法,查看運行結(jié)果

3.4 作用于參數(shù)上

3.4.1 改造 Person 類

@Component
public class Person {

    @Autowired
    @Qualifier("car666")
    private Car car;

    private Animal animal;

    public Person(@Qualifier("wangcai") Animal animal) {
        this.animal = animal;
    }
}

3.4.2 運行 main 方法,查看運行結(jié)果

3.5 作用于注解上

3.5.1 創(chuàng)建自定義注解 NestQualifier

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface NestQualifier {
    @AliasFor(annotation = Qualifier.class, attribute = "value")
    String value() default "";

}

3.5.2 自定義注解的使用

3.5.2.1 改造 Person 類

@Component
public class Person {

    @Autowired
    @NestQualifier("redCar")
    private Car car;

    private Animal animal;

    public Person(@Qualifier("wangcai") Animal animal) {
        this.animal = animal;
    }
}

3.5.2.2 改造 Person、RedCar 類

@Component
public class Person {

    @Autowired
    @NestQualifier("car666")
    private Car car;

    private Animal animal;

    public Person(@Qualifier("wangcai") Animal animal) {
        this.animal = animal;
    }
}

@Component
@NestQualifier("car666")
public class RedCar implements Car {
}

3.5.3 運行main方法,查看運行結(jié)果

3.6 小結(jié)

  • 作用于方法上、作用于類上等于給 bean 添加了一個 alias
  • 作用于屬性上、作用于參數(shù)上時等于注入指定標(biāo)識符的 bean,這個標(biāo)識符既可以是 beanName,也可以是 alias
  • 作用于注解上比較特殊,如果作用于方法上、作用于類上時用了包裝注解,作用于屬性上、作用于參數(shù)上也必須使用包裝注解,否則標(biāo)識符只能使用 beanName,使用 alias 會報錯

4. 源碼解析

4.1 QualifierAnnotationAutowireCandidateResolver#checkQualifier

protected boolean checkQualifier(BeanDefinitionHolder bdHolder, Annotation annotation, TypeConverter typeConverter) {

    Class<? extends Annotation> type = annotation.annotationType();
    RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition();

    // 這里以@NestQualifier注解為例
    // 判斷是否存在名稱為com.test.qualifier.annotations.NestQualifier的AutowireCandidateQualifier
    AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());
    if (qualifier == null) {
        // 判斷是否存在名稱為NestQualifier的AutowireCandidateQualifier
        qualifier = bd.getQualifier(ClassUtils.getShortName(type));
    }
    if (qualifier == null) {
        // 判斷bd的qualifiedElement,是否存在@NestQualifier注解
        Annotation targetAnnotation = getQualifiedElementAnnotation(bd, type);

        // 判斷bd的factoryMethod,是否存在@NestQualifier注解
        // PS:即@Bean標(biāo)注的方法上是否存在@NestQualifier注解
        if (targetAnnotation == null) {
            targetAnnotation = getFactoryMethodAnnotation(bd, type);
        }
        // 判斷bd是否存在裝飾器bd,然后判斷裝飾器bd的factoryMethod,是否存在@NestQualifier注解
        if (targetAnnotation == null) {
            RootBeanDefinition dbd = getResolvedDecoratedDefinition(bd);
            if (dbd != null) {
                targetAnnotation = getFactoryMethodAnnotation(dbd, type);
            }
        }

        // 判斷bd的實際類型是否存在@NestQualifier注解
        if (targetAnnotation == null) {
            // Look for matching annotation on the target class
            if (getBeanFactory() != null) {
                try {
                    Class<?> beanType = getBeanFactory().getType(bdHolder.getBeanName());
                    if (beanType != null) {
                        targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(beanType), type);
                    }
                } catch (NoSuchBeanDefinitionException ex) {
                    // Not the usual case - simply forget about the type check...
                }
            }

            // 判斷bd的實際類型是否存在@NestQualifier注解,這里主要針對沒有傳入beanFactory的情況
            if (targetAnnotation == null && bd.hasBeanClass()) {
                targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(bd.getBeanClass()), type);
            }
        }

        // 如果目標(biāo)注解等于方法傳入的注解,則返回true
        // 即屬性注入的value值和類上或者方法上的value值一致,則返回true
        if (targetAnnotation != null && targetAnnotation.equals(annotation)) {
            return true;
        }
    }

    Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
    if (attributes.isEmpty() && qualifier == null) {
        // If no attributes, the qualifier must be present
        return false;
    }
    for (Map.Entry<String, Object> entry : attributes.entrySet()) {
        // 獲取注解的屬性和屬性值
        String attributeName = entry.getKey();
        Object expectedValue = entry.getValue();
        Object actualValue = null;
        // 通過qualifier獲取actualValue
        if (qualifier != null) {
            actualValue = qualifier.getAttribute(attributeName);
        }
        // 通過bd獲取actualValue
        if (actualValue == null) {
            // Fall back on bean definition attribute
            actualValue = bd.getAttribute(attributeName);
        }
        // 即屬性注入的value值和beanName的值相等則,返回true
        if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) &&
                expectedValue instanceof String && bdHolder.matchesName((String) expectedValue)) {
            // Fall back on bean name (or alias) match
            continue;
        }
        // actualValue等于null,qualifier不等于null,獲取value的默認(rèn)值
        if (actualValue == null && qualifier != null) {
            // Fall back on default, but only if the qualifier is present
            actualValue = AnnotationUtils.getDefaultValue(annotation, attributeName);
        }
        if (actualValue != null) {
            actualValue = typeConverter.convertIfNecessary(actualValue, expectedValue.getClass());
        }
        // 判斷@NestQualifier注解設(shè)置的值是否與默認(rèn)值相等
        if (!expectedValue.equals(actualValue)) {
            return false;
        }
    }
    return true;
}

4.2 通過 BeanFactoryPostProcessor 來設(shè)置上述源碼中的一些值

@Component
public class FirstBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        ScannedGenericBeanDefinition scannedGenericBeanDefinition = (ScannedGenericBeanDefinition) registry.getBeanDefinition("redCar");

        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClassName(scannedGenericBeanDefinition.getBeanClassName());

        // 設(shè)置qualifiedElement
        beanDefinition.setQualifiedElement(RedCar.class);

        AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(NestQualifier.class);
        // 通過qualifier設(shè)置actualValue
        qualifier.setAttribute("value", "whiteCar");
        beanDefinition.addQualifier(qualifier);

        // 通過bd設(shè)置actualValue
        beanDefinition.setAttribute("value", "redCar");

        registry.registerBeanDefinition("redCar", beanDefinition);

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

    }
}

PS : 被 @ComponentScan 注解掃描的帶有 @Component 注解的類會被解析成ScannedGenericBeanDefinition,但是 Spring 在實例化 bean 的時候會把所有 BeanDefinition 封裝成 RootBeanDefinition 處理,如果不提前改造 BeanDefinition 的話,RootBeanDefinition 屬性都是默認(rèn)值

到此這篇關(guān)于Spring之@Qualifier注解的具體使用的文章就介紹到這了,更多相關(guān)Spring @Qualifier注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中import java.util.Scanner的用處詳解

    Java中import java.util.Scanner的用處詳解

    文章主要介紹Java中的Scanner類及其常用方法next()和nextLine()的區(qū)別,next()方法在遇到空格、Tab鍵、回車鍵等分隔符時結(jié)束輸入,而nextLine()方法則接收所有輸入,直到遇到回車鍵
    2024-11-11
  • springboot 在idea中實現(xiàn)熱部署的方法

    springboot 在idea中實現(xiàn)熱部署的方法

    這篇文章主要介紹了springboot 在idea中實現(xiàn)熱部署的方法,實現(xiàn)了熱部署,在每一次作了修改之后,都會自動的重啟,非常節(jié)約時間,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Map獲取鍵值,Map的幾種遍歷方法總結(jié)(推薦)

    Map獲取鍵值,Map的幾種遍歷方法總結(jié)(推薦)

    下面小編就為大家?guī)硪黄狹ap獲取鍵值,Map的幾種遍歷方法總結(jié)(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • SpringBoot redis分布式緩存實現(xiàn)過程解析

    SpringBoot redis分布式緩存實現(xiàn)過程解析

    這篇文章主要介紹了SpringBoot redis分布式緩存實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • SpringBoot+本地消息表實現(xiàn)分布式最終一致性

    SpringBoot+本地消息表實現(xiàn)分布式最終一致性

    本文主要介紹了SpringBoot+本地消息表實現(xiàn)分布式最終一致性,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-02-02
  • java ThreadPoolExecutor線程池拒絕策略避坑

    java ThreadPoolExecutor線程池拒絕策略避坑

    這篇文章主要為大家介紹了java ThreadPoolExecutor拒絕策略避坑踩坑示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Spring Cloud接口突然變慢的解決方案

    Spring Cloud接口突然變慢的解決方案

    在Spring Cloud項目中,接口突然變慢可能是由多種原因造成的,本文給大家介紹了一些可能的原因以及相應(yīng)的解決方案,通過代碼示例給大家講解的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • java發(fā)送飛書消息卡片具體實現(xiàn)方法

    java發(fā)送飛書消息卡片具體實現(xiàn)方法

    這篇文章主要介紹了java發(fā)送飛書消息卡片具體實現(xiàn)方法的相關(guān)資料,Java通過飛書消息卡片API,可以高效解決傳統(tǒng)消息推送方式的痛點,實現(xiàn)業(yè)務(wù)系統(tǒng)事件與飛書消息卡片之間的全流程閉環(huán),需要的朋友可以參考下
    2026-03-03
  • 純Java類配置與@Configuration實戰(zhàn)指南

    純Java類配置與@Configuration實戰(zhàn)指南

    本文介紹@Configuration的核心用法,實戰(zhàn)@Bean定義Bean、@ComponentScan掃描組件、@Import組合配置類,帶大家體驗“無XML”的Spring配置新方式,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • 關(guān)于ThreadLocal對request和response的用法說明

    關(guān)于ThreadLocal對request和response的用法說明

    這篇文章主要介紹了關(guān)于ThreadLocal對request和response的用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08

最新評論

眉山市| 万宁市| 德安县| 奎屯市| 金山区| 横山县| 天峻县| 丰原市| 乐都县| 铜梁县| 阳城县| 巧家县| 衡水市| 龙南县| 章丘市| 醴陵市| 杭州市| 南昌县| 兖州市| 西平县| 九龙县| 扶绥县| 达日县| 河西区| 广灵县| 乌苏市| 陇南市| 洪洞县| 房山区| 万宁市| 宝清县| 会宁县| 九龙城区| 迭部县| 临泉县| 武鸣县| 洱源县| 阿尔山市| 普安县| 阿尔山市| 小金县|