BeanFactoryAnnotationUtils:提供与注解相关的查找Bean的方法(比如@Qualifier)
讲解它之前,先看看这个工具类:BeanFactoryUtils:
BeanFactoryUtils:方便在Bean工厂上操作的工具类,特别针对于ListableBeanFactory这个工厂
public abstract class BeanFactoryUtils { // 内部生成BeanName的分隔符,如果不唯一后面会一直加这个符号 public static final String GENERATED_BEAN_NAME_SEPARATOR = "#"; // 判断这个Bean是不是工厂Bean FactoryBean public static boolean isFactoryDereference(@Nullable String name) { return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)); } // 得到真实的Bean的名称(兼容工厂Bean的情况) public static String transformedBeanName(String name) { Assert.notNull(name, "'name' must not be null"); String beanName = name; while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } return beanName; } // 是否是BeanDefinitionReaderUtils#generateBeanName生成出来的Bean名字 public static boolean isGeneratedBeanName(@Nullable String name) { return (name != null && name.contains(GENERATED_BEAN_NAME_SEPARATOR)); } // 包含祖先(父工厂) bean的总数目 public static int countBeansIncludingAncestors(ListableBeanFactory lbf) { return beanNamesIncludingAncestors(lbf).length; } // bean的所有的名称 会做去重处理 public static String[] beanNamesIncludingAncestors(ListableBeanFactory lbf) { return beanNamesForTypeIncludingAncestors(lbf, Object.class); } // 显然依赖的方法都是ListableBeanFactory#getBeanNamesForType public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, ResolvableType type) { Assert.notNull(lbf, "ListableBeanFactory must not be null"); String[] result = lbf.getBeanNamesForType(type); if (lbf instanceof HierarchicalBeanFactory) { HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { // 递归去获取 String[] parentResult = beanNamesForTypeIncludingAncestors( (ListableBeanFactory) hbf.getParentBeanFactory(), type); // 做名字的合并、去重处理 result = mergeNamesWithParent(result, parentResult, hbf); } } return result; } public static <T> T beanOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<T> type){ ... } // 这个方法是关于注解的,需要注意一些========Spring5.0后才有的 public static String[] beanNamesForAnnotationIncludingAncestors( ListableBeanFactory lbf, Class<? extends Annotation> annotationType) { Assert.notNull(lbf, "ListableBeanFactory must not be null"); String[] result = lbf.getBeanNamesForAnnotation(annotationType); if (lbf instanceof HierarchicalBeanFactory) { HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { String[] parentResult = beanNamesForAnnotationIncludingAncestors( (ListableBeanFactory) hbf.getParentBeanFactory(), annotationType); result = mergeNamesWithParent(result, parentResult, hbf); } } return result; } public static <T> T beanOfType(ListableBeanFactory lbf, Class<T> type){ ... } }
总之这个Util里面就是提供了一些便捷从ListableBeanFactory
里面获取Bean的方法(包含了父容器,默认实现都是不去父容器里找的)
BeanFactoryAnnotationUtils
public abstract class BeanFactoryAnnotationUtils { // 检查beanName这个Bean是否匹配。或者标注了@Qualifier注解,名称是否匹配 public static boolean isQualifierMatch(Predicate<String> qualifier, String beanName, @Nullable BeanFactory beanFactory) { // Try quick bean name or alias match first... // 若BeanName匹配,那就快速返回 if (qualifier.test(beanName)) { return true; } if (beanFactory != null) { // 若有alias别名匹配上了,也可以快速返回 for (String alias : beanFactory.getAliases(beanName)) { if (qualifier.test(alias)) { return true; } } try { if (beanFactory instanceof ConfigurableBeanFactory) { // 拿到和父类(若存在)合并后的定义信息 BeanDefinition bd = ((ConfigurableBeanFactory) beanFactory).getMergedBeanDefinition(beanName); // Explicit qualifier metadata on bean definition? (typically in XML definition) if (bd instanceof AbstractBeanDefinition) { AbstractBeanDefinition abd = (AbstractBeanDefinition) bd; AutowireCandidateQualifier candidate = abd.getQualifier(Qualifier.class.getName()); // 如果有@Qualifier 并且匹配上了 就返回true if (candidate != null) { Object value = candidate.getAttribute(AutowireCandidateQualifier.VALUE_KEY); if (value != null && qualifier.test(value.toString())) { return true; } } } // Corresponding qualifier on factory method? (typically in configuration class) // 若FactoryMethod工厂方法里有此注解,匹配上了也返回true if (bd instanceof RootBeanDefinition) { Method factoryMethod = ((RootBeanDefinition) bd).getResolvedFactoryMethod(); if (factoryMethod != null) { Qualifier targetAnnotation = AnnotationUtils.getAnnotation(factoryMethod, Qualifier.class); if (targetAnnotation != null) { return qualifier.test(targetAnnotation.value()); } } } } // Corresponding qualifier on bean implementation class? (for custom user types) // 若自己本类上标注了此注解,匹配上了 肯定也是返回true的... //上面的解析相当于配置的情况,而这种情况就是在本类上直接标注~~~(备注:@Qualifier可以标注在类上,作用就体现在这里了) Class<?> beanType = beanFactory.getType(beanName); if (beanType != null) { Qualifier targetAnnotation = AnnotationUtils.getAnnotation(beanType, Qualifier.class); if (targetAnnotation != null) { return qualifier.test(targetAnnotation.value()); } } } catch (NoSuchBeanDefinitionException ex) { } } return false; } } // 就根据beanType、qualifier找到一个唯一的Bean(因为该type的可能有很多) // 目前只有CacheAspectSupport#getBean等少量用到 public static <T> T qualifiedBeanOfType(BeanFactory beanFactory, Class<T> beanType, String qualifier){ ... }
此处一定注意@Qualifier
的使用场景,它是可以直接标注在类上的。看下面例子解说:
@Service public class HelloServiceImpl implements HelloService { } @Controller public class HelloController { @Autowired @Qualifier("aaa") // 因为不存在aaa的bean,所以肯定会报错的 private HelloService helloService; } 但是,我们只需要在HelloServiceImpl 也加上对应的注解`@Qualifier`就不会报错了(但强烈不建议这么写,需要注意) @Service @Qualifier("aaa") // 这样上面的HelloService 注入就不会报错了 public class HelloServiceImpl implements HelloService { }
需要注意的是,虽然HelloServiceImpl 上加了此注解,但是它在Bean工厂里的BeanName可不会变。但是它在匹配的时候就能匹配上了,这就是BeanFactoryAnnotationUtils#isQualifierMatch的功劳
最后再讨论讨论注解中常常使用的AnnotationAttributes类
AnnotationAttributes:Map的封装,在实际使用时会有更好的体验
它的获取一般这么来:
- AnnotatedTypeMetadata#getAnnotationAttributes
- AnnotationAttributes#fromMap
- AnnotatedElementUtils#getMergedAnnotationAttributes等系列方法
- new AnnotationAttributes
public class AnnotationAttributes extends LinkedHashMap<String, Object> { // 持有对应注解的类型的引用 @Nullable private final Class<? extends Annotation> annotationType; final String displayName; // 多个构造函数 public AnnotationAttributes(AnnotationAttributes other) { super(other); this.annotationType = other.annotationType; this.displayName = other.displayName; this.validated = other.validated; } // 把一个注解类型Class,直接包装成AnnotationAttributes public AnnotationAttributes(Class<? extends Annotation> annotationType) { Assert.notNull(annotationType, "'annotationType' must not be null"); this.annotationType = annotationType; this.displayName = annotationType.getName(); } ... // 获得它所属的注解类型 @Nullable public Class<? extends Annotation> annotationType() { return this.annotationType; } public String getString(String attributeName) { return getRequiredAttribute(attributeName, String.class); } public String[] getStringArray(String attributeName) { return getRequiredAttribute(attributeName, String[].class); } ... // 这个使用得比较多,因为AnnotationMetadata#getAnnotationAttributes返回的是Map值 @Nullable public static AnnotationAttributes fromMap(@Nullable Map<String, Object> map) { if (map == null) { return null; } //大部分情况在整理就return了,否则继续下面,annotationType就为null,那就是普通的Map里 if (map instanceof AnnotationAttributes) { return (AnnotationAttributes) map; } return new AnnotationAttributes(map); } }
总结
本文主要讲解了一下Spirng体系里和注解相关的工具类。因为在注解驱动大行其道的今天,个人认为有必要去了解Spring解析注解的一些方式、方法等。
Spring易学难精是得以与他优秀的设计:分层、封装、扩展、包访问权限管理等等,在各处都有所体现