欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring之@Qualifier注解的具體使用

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

1. 前言

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

2. demo 演示

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

public interface Car {
}

@Component
public class RedCar implements Car {
}

@Component
public class WhiteCar implements Car {
}

2.2 創(chuàng)建實(shí)體類 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 運(yùn)行main方法

啟動(dòng)過(guò)程,拋出異常

2.5 解決方法

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

3. @Qualifier 注解源碼

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

3.1 作用于屬性上

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

3.1.1 改造 Person 類

@Component
public class Person {

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

}

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

3.2 作用于方法上

3.2.1 創(chuàng)建一個(gè)接口 Animal,以及兩個(gè)實(shí)現(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 運(yùn)行main方法,查看運(yùn)行結(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 運(yùn)行 main 方法,查看運(yùn)行結(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 運(yùn)行 main 方法,查看運(yùn)行結(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 運(yùn)行main方法,查看運(yùn)行結(jié)果

3.6 小結(jié)

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

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的實(shí)際類型是否存在@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的實(shí)際類型是否存在@NestQualifier注解,這里主要針對(duì)沒(méi)有傳入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;
        // 通過(guò)qualifier獲取actualValue
        if (qualifier != null) {
            actualValue = qualifier.getAttribute(attributeName);
        }
        // 通過(guò)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 通過(guò) BeanFactoryPostProcessor 來(lái)設(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);
        // 通過(guò)qualifier設(shè)置actualValue
        qualifier.setAttribute("value", "whiteCar");
        beanDefinition.addQualifier(qualifier);

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

        registry.registerBeanDefinition("redCar", beanDefinition);

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

    }
}

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

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

相關(guān)文章

  • 最值得Java開發(fā)者收藏的網(wǎng)站

    最值得Java開發(fā)者收藏的網(wǎng)站

    這篇文章主要為大家分享了最值得Java開發(fā)者收藏的11個(gè)網(wǎng)站,幫助Java開發(fā)者提升編程能力
    2016-11-11
  • java面向?qū)ο蟮牧瓌t一法則小結(jié)

    java面向?qū)ο蟮牧瓌t一法則小結(jié)

    本篇文章主要對(duì)java面向?qū)ο蟮牧瓌t一法則進(jìn)行簡(jiǎn)要說(shuō)明,具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-01-01
  • spring boot如何基于JWT實(shí)現(xiàn)單點(diǎn)登錄詳解

    spring boot如何基于JWT實(shí)現(xiàn)單點(diǎn)登錄詳解

    這篇文章主要介紹了spring boot如何基于JWT實(shí)現(xiàn)單點(diǎn)登錄詳解,用戶只需登錄一次就能夠在這兩個(gè)系統(tǒng)中進(jìn)行操作。很明顯這就是單點(diǎn)登錄(Single Sign-On)達(dá)到的效果,需要的朋友可以參考下
    2019-06-06
  • Java實(shí)現(xiàn)讀取Jar文件屬性的方法詳解

    Java實(shí)現(xiàn)讀取Jar文件屬性的方法詳解

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語(yǔ)言實(shí)現(xiàn)讀取Jar文件屬性的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-08-08
  • springMVC如何將controller中Model數(shù)據(jù)傳遞到j(luò)sp頁(yè)面

    springMVC如何將controller中Model數(shù)據(jù)傳遞到j(luò)sp頁(yè)面

    本篇文章主要介紹了springMVC如何將controller中Model數(shù)據(jù)傳遞到j(luò)sp頁(yè)面,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-07-07
  • spring聲明式事務(wù)解析

    spring聲明式事務(wù)解析

    這篇文章主要為大家詳細(xì)介紹了spring聲明式事務(wù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • Java Mybatis一級(jí)緩存和二級(jí)緩存

    Java Mybatis一級(jí)緩存和二級(jí)緩存

    緩存是內(nèi)存當(dāng)中一塊存儲(chǔ)數(shù)據(jù)的區(qū)域,目的是提高查詢效率,降低服務(wù)器和數(shù)據(jù)庫(kù)的壓力,這篇文章主要介紹了Mybatis一級(jí)緩存和二級(jí)緩存,感興趣的同學(xué)可以參考閱讀本文
    2023-04-04
  • Java之HashMap案例詳解

    Java之HashMap案例詳解

    這篇文章主要介紹了Java之HashMap案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • 深入淺析Mybatis的缺陷問(wèn)題

    深入淺析Mybatis的缺陷問(wèn)題

    Mybatis是業(yè)界非常流行的持久層框架,輕量級(jí)、易用,在金融IT領(lǐng)域完全是領(lǐng)軍地位,比Hibernate更受歡迎,優(yōu)勢(shì)非常多,也是非常值得我們學(xué)習(xí)的。這篇文章主要介紹了Mybatis的缺陷問(wèn)題的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • Java與Kotlin互調(diào)原理講解

    Java與Kotlin互調(diào)原理講解

    這篇文章主要介紹了Java與Kotlin互調(diào)原理,分享內(nèi)容有Kt調(diào)用-Java參數(shù)非null的處理、Java中使用kt關(guān)鍵字聲明的變量和方法、Kt調(diào)用Java-SAM轉(zhuǎn)換等內(nèi)容,需要的小伙伴可以參考一下
    2022-02-02

最新評(píng)論