当前位置: 代码网 > it编程>编程语言>Java > Spring之@Qualifier注解的具体使用

Spring之@Qualifier注解的具体使用

2024年08月18日 Java 我要评论
1. 前言当我们注入的依赖存在多个候选者,我们得使用一些方法来筛选出唯一候选者,否则就会抛出异常2. demo 演示2.1 创建接口 car,以及两个实现其接口的子类public interface

1. 前言

当我们注入的依赖存在多个候选者,我们得使用一些方法来筛选出唯一候选者,否则就会抛出异常

2. demo 演示

2.1 创建接口 car,以及两个实现其接口的子类

public interface car {
}

@component
public class redcar implements car {
}

@component
public class whitecar implements car {
}

2.2 创建实体类 person

@component
public class person {

    @autowired
    private car car;
}

2.3 创建配置类以及 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 注解源码

 从源码中我们知道这个注解可以作用于属性、方法、参数、类、注解上面

3.1 作用于属性上

我们以 demo 演示代码为前提,使用 @qualifier 注解

3.1.1 改造 person 类

@component
public class person {

    @autowired
    @qualifier("redcar")
    private car car;

}

 3.1.2 运行main方法,查看运行结果

3.2 作用于方法上

3.2.1 创建一个接口 animal,以及两个实现类

public interface animal {
}

public class dog implements animal {
}

public class cat implements animal {
}

3.2.2 创建配置类

@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方法,查看运行结果

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 方法,查看运行结果

3.4 作用于参数上

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 方法,查看运行结果

3.5 作用于注解上

3.5.1 创建自定义注解 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方法,查看运行结果

3.6 小结

  • 作用于方法上、作用于类上等于给 bean 添加了一个 alias
  • 作用于属性上、作用于参数上时等于注入指定标识符的 bean,这个标识符既可以是 beanname,也可以是 alias
  • 作用于注解上比较特殊,如果作用于方法上、作用于类上时用了包装注解,作用于属性上、作用于参数上也必须使用包装注解,否则标识符只能使用 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标注的方法上是否存在@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);
            }
        }

        // 如果目标注解等于方法传入的注解,则返回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的默认值
        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注解设置的值是否与默认值相等
        if (!expectedvalue.equals(actualvalue)) {
            return false;
        }
    }
    return true;
}

4.2 通过 beanfactorypostprocessor 来设置上述源码中的一些值

@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());

        // 设置qualifiedelement
        beandefinition.setqualifiedelement(redcar.class);

        autowirecandidatequalifier qualifier = new autowirecandidatequalifier(nestqualifier.class);
        // 通过qualifier设置actualvalue
        qualifier.setattribute("value", "whitecar");
        beandefinition.addqualifier(qualifier);

        // 通过bd设置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 属性都是默认值

到此这篇关于spring之@qualifier注解的具体使用的文章就介绍到这了,更多相关spring @qualifier注解内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com