当我们注入的依赖存在多个候选者,我们得使用一些方法来筛选出唯一候选者,否则就会抛出异常
demo演示
创建接口Car,以及两个实现其接口的bean
public interface Car { } @Component public class RedCar implements Car { } @Component public class WhiteCar implements Car { }
创建类型为Person的bean
@Component public class Person { @Autowired private Car car; }
创建配置类以及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); } }
运行main方法
解决方法
从源码中我们知道这个注解可以作用于属性、方法、参数、类、注解上面
我们以demo演示代码为前提,使用@Qualifier注解
改造Person类
@Component public class Person { @Autowired @Qualifier("redCar") private Car car; }
运行main方法,查看运行结果
创建一个接口Animal,以及两个实现类
public interface Animal { } public class Dog implements Animal { } public class Cat implements Animal { }
创建配置类
@Configuration public class AnimalConfig { @Bean @Qualifier("mimi") public Cat cat(){ return new Cat(); } @Bean @Qualifier("wangcai") public Dog dog(){ return new Dog(); } }
改造Person类
@Component public class Person { @Autowired @Qualifier("redCar") private Car car; @Autowired @Qualifier("mimi") private Animal animal; }
运行main方法,查看运行结果
改造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; }
运行main方法,查看运行结果
改造Person类
@Component public class Person { @Autowired @Qualifier("car666") private Car car; private Animal animal; public Person(@Qualifier("wangcai") Animal animal) { this.animal = animal; } }
运行main方法,查看运行结果
创建自定义注解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 ""; }
case1:改造Person类
@Component public class Person { @Autowired @NestQualifier("redCar") private Car car; private Animal animal; public Person(@Qualifier("wangcai") Animal animal) { this.animal = animal; } }
case2:改造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 { }
运行main方法,查看运行结果
作用于方法上、作用于类上等于给bean添加了一个alias,作用于属性上、作用于参数上时等于注入指定标识符的bean,这个标识符既可以是beanName,也可以是alias。作用于注解上比较特殊,如果作用于方法上、作用于类上时用了包装注解,作用于属性上、作用于参数上也必须使用包装注解,否则标识符只能使用beanName,使用alias会报错
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; } } Mapattributes = AnnotationUtils.getAnnotationAttributes(annotation); if (attributes.isEmpty() && qualifier == null) { // If no attributes, the qualifier must be present return false; } for (Map.Entry 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; }
上述源码的一些值需要通过bfpp来设置
@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的时候会把所有bd封装成RootBeanDefinition处理,如果不提前改造bd的话,RootBeanDefinition属性都是默认值
上一篇:【MySQL】lower