它的fallback策略最多只能再向上再找一个层级(多了就不行了)。例如上例子中使用@B标注也是能起到@Qualifier效果的,但是若再加一个@C层级,限定符就不生效了。
注意:Class.isAnnotationPresent(Class<? extends Annotation> annotationClass)表示annotationClass是否标注在此类型上(此类型可以是任意Class类型)。
此方法不具有传递性:比如注解A上标注有@Qualifier,注解B上标注有@A注解,那么你用此方法判断@B上是否有@Qualifier它是返回false的(即使都写了@Inherited注解,因为和它没关系)
到这其实还是不能解释本文中为何@LoadBalanced参与了依赖注入,还得继续看精髓中的精髓checkQualifier()方法(方法名是单数,表示精确检查某一个单独的注解):
QualifierAnnotationAutowireCandidateResolver: // 检查某一个注解限定符,是否匹配当前的Bean protected boolean checkQualifier(BeanDefinitionHolder bdHolder, Annotation annotation, TypeConverter typeConverter) { // type:注解类型 bd:当前Bean的RootBeanDefinition Class<? extends Annotation> type = annotation.annotationType(); RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition(); // ========下面是匹配的关键步骤========= // 1、Bean定义信息的qualifiers字段一般都无值了(XML时代的配置除外) // 长名称不行再拿短名称去试了一把。显然此处 qualifier还是为null的 AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName()); if (qualifier == null) { qualifier = bd.getQualifier(ClassUtils.getShortName(type)); } //这里才是真真有料的地方~~~请认真看步骤 if (qualifier == null) { // First, check annotation on qualified element, if any // 1、词方法是从bd标签里拿这个类型的注解声明,非XML配置时代此处targetAnnotation 为null Annotation targetAnnotation = getQualifiedElementAnnotation(bd, type); // Then, check annotation on factory method, if applicable // 2、若为null。去工厂方法里拿这个类型的注解。这方法里标注了两个注解@Bean和@LoadBalanced,所以此时targetAnnotation就不再为null了~~ if (targetAnnotation == null) { targetAnnotation = getFactoryMethodAnnotation(bd, type); } // 若本类木有,还会去父类去找一趟 if (targetAnnotation == null) { RootBeanDefinition dbd = getResolvedDecoratedDefinition(bd); if (dbd != null) { targetAnnotation = getFactoryMethodAnnotation(dbd, type); } } // 若xml、工厂方法、父里都还没找到此方法。那好家伙,回退到还去类本身上去看 // 也就是说,如果@LoadBalanced标注在RestTemplate上,也是阔仪的 if (targetAnnotation == null) { // Look for matching annotation on the target class ... } // 找到了,并且当且仅当就是这个注解的时候,就return true了~ // Tips:这里使用的是equals,所以即使目标的和Bean都标注了@Qualifier属性,value值相同才行哟~~~~ // 简单的说:只有value值相同,才会被选中的。否则这个Bean就是不符合条件的 if (targetAnnotation != null && targetAnnotation.equals(annotation)) { return true; } } // 赞。若targetAnnotation还没找到,也就是还没匹配上。仍旧还不放弃,拿到当前这个注解的所有注解属性继续尝试匹配 Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation); if (attributes.isEmpty() && qualifier == null) { return false; } ... // 详情不描述了。这就是为什么我们吧@Qualifier标注在某个类上面都能生效的原因 就是这里做了非常强大的兼容性~ } // =================它最重要的两个判断================= if (targetAnnotation != null && targetAnnotation.equals(annotation)); // Fall back on bean name (or alias) match if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) && expectedValue instanceof String && bdHolder.matchesName((String) expectedValue));
checkQualifier()方法的实现,足以看到Spring作为一个优秀框架它对case的全面性,兼容性、灵活性的考虑还是很到位的。正因为Spring提供的强大的支持和灵活扩展,才给与了SpringBoot、SpringCloud在框架层面设计上更多可能性~