本文主要聊聊Spring提供的多个关于注解相关的工具类:AnnotationUtils
和AnnotatedElementUtils
等等
因为很多逻辑都封装在了工具类里面,因此要理解Spring的深层意思,有时候不了解工具类也是比较麻烦的
虽然说都是Spring内部去使用,但是有些工具类是public的(下面会有介绍),所以我们平时若有需要,也是可以使用的
本文要说明的工具类如上图,一共会讲述9个(排名不分先后)。(ParserStrategyUtils
忽略,没什么好说的,只有一个方法处理Aware的注入。AnnotationReadingVisitorUtils
也忽略,它和ASM
字节码相关,后面再讨论)
AnnotationUtils
(最重要)总之,从类名就能看出来。这是Spring提供的获取、处理注解的工具类。 可能有小伙伴就非常好奇了:JDK已经提供给我们获取注解的方法了,Spring为何要多此一举呢?如下:
@MyAnno
interface Eat {
}
class Parent implements Eat {
}
class Child extends Parent {
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping // 特意注解上放一个注解,方面测试看结果
@Inherited
@interface MyAnno {
}
// 现在我们来获取类上面的注解如下
public static void main(String[] args) {
MyAnno anno1 = Eat.class.getAnnotation(MyAnno.class);
MyAnno anno2 = Parent.class.getAnnotation(MyAnno.class);
MyAnno anno3 = Child.class.getAnnotation(MyAnno.class);
System.out.println(anno1); //@com.fsx.maintest.MyAnno()
System.out.println(anno2); //null
System.out.println(anno3); //null
}
此处必须对结果说明一点:我们的注解标注了
@Inherited
表示该注解可以被继承,但是anno2和anno3还是null。需要注意:@Inherited
继承只能发生在类上,而不能发生在接口上(也就是说标注在接口上仍然是不能被继承的)
<A extends Annotation>A getAnnotation(Class<A>annotationClass)
:获取该class对象对应类上指定类型的Annotation,如果该类型注解不存在,则返回nullAnnotation[] getAnnotations()
:返回修饰该class对象对应类上存在的所有Annotation<A extends Annotation>A getDeclaredAnnotation(Class<A>annotationClass)
:这是Java 8中新增的,该方法获取直接修饰该class对象对应类的指定类型的Annotation,如果不存在,则返回null(也就说只找自己的,继承过来的注解这个方法就不管了)<A extends Annotation>A[] getAnnotationByType(Class<A>annotationClass)
:该方法的功能与前面介绍的getAnnotation()方法基本相似,但由于Java8增加了重复注解功能
,因此需要使用该方法获取修饰该类的指定类型的多个Annotation(会考虑继承的注解
)<A extends Annotation>A[] getDeclaredAnnotationByType(Class<A>annotationClass)
:相信不解释你也懂更多Class中的方法使用,请参阅:Java反射获取类和对象信息全解析
既然JDK提供给了我们这么多的注解相关方法,乍一看是够用了呢?为何Spring还自己写个工具类呢?我觉得这也是Spring的强大之处,往往写出来的东西比JDK的还强大。比如试想一下下面两个场景,你就没觉得疑惑?
@AliasFor(Spring4.2之后才有的)
为何能生效呢?大大的方便了我们注解的使用@RequestMapping
注解明明不能继承(即使有@Inherited
也不能写在接口上嘛),但为何我们把它写在接口上时,用Controller去实现的时候却像是被继承了一样呢?注解支持的数据类型:
所有基本类型(int,float,boolean,byte,double,char,long,short) 注意:包装类型不支持
上述类型的数组
注解是不支持继承的,因此不能使用关键字extends来继承某个@interface,但注解在编译后,编译器会自动继承
java.lang.annotation.Annotation
接口(从反编译代码里可以看出,类似于Enum)
*如果你不能解释至少上面两个疑问,那么你就很有必要来看看这个工具类了~~~~*
AnnotationUtils
内部使用了很多ConcurrentReferenceHashMap(弱、软引用)作为缓存,来各种提高效率
开门见山,先直接上一个最强的方法,也是该工具类的核心:synthesizeAnnotation
static <A extends Annotation> A synthesizeAnnotation(A annotation) {
return synthesizeAnnotation(annotation, null);
}
public static <A extends Annotation> A synthesizeAnnotation(
A annotation, @Nullable AnnotatedElement annotatedElement) {
return synthesizeAnnotation(annotation, (Object) annotatedElement);
}
static <A extends Annotation> A synthesizeAnnotation(A annotation, @Nullable Object annotatedElement) {
if (annotation instanceof SynthesizedAnnotation) {
return annotation;
}
Class<? extends Annotation> annotationType = annotation.annotationType();
if (!isSynthesizable(annotationType)) {
return annotation;
}
DefaultAnnotationAttributeExtractor attributeExtractor =
new DefaultAnnotationAttributeExtractor(annotation, annotatedElement);
InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);
// Can always expose Spring's SynthesizedAnnotation marker since we explicitly check for a
// synthesizable annotation before (which needs to declare @AliasFor from the same package)
Class<?>[] exposedInterfaces = new Class<?>[] {annotationType, SynthesizedAnnotation.class};
return (A) Proxy.newProxyInstance(annotation.getClass().getClassLoader(), exposedInterfaces, handler);
}
作用:来获取一个动态代理注解(相当于调用者传进来的注解会被代理掉),该方法是别名注解@AliasFor
的核心原理。
public static <A extends Annotation> A getAnnotation(Annotation annotation, Class<A> annotationType)
: public static void main(String[] args) {
MyAnno anno1 = Eat.class.getAnnotation(MyAnno.class);
// 注解交给这么一处理 相当于就会被Spring代理了 这就是优势
MyAnno sAnno1 = AnnotationUtils.getAnnotation(anno1, MyAnno.class);
System.out.println(sAnno1); //@com.fsx.maintest.MyAnno()
// 这样前后类型不一致的话,会把这个注解上面的注解给获取出来
RequestMapping annotation = AnnotationUtils.getAnnotation(anno1, RequestMapping.class);
System.out.println(annotation); //@org.springframework.web.bind.annotation.RequestMapping
}
public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType)
:重载方法。上面annotation.annotationType();
其实就是annotatedElement了public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType)
:强大之处在于:它连桥接方法(BridgeMethod)
都支持。参考;java中什么是bridge method(桥接方法)public static Annotation[] getAnnotations(AnnotatedElement annotatedElement)
:获取指定类型上所有注解 public static void main(String[] args) {
MyAnno anno1 = Eat.class.getAnnotation(MyAnno.class);
// 注意这两种写法的区别:
// 这个相当于是获取Child.class的它上面的所有注解, 所以只有继承过来的一个@MyAnno
Annotation[] sAnno1 = AnnotationUtils.getAnnotations(Child.class);
// 而这里传入的为anno1.annotationType,所以相当于获取该注解上面的注解 所以使用的时候需要注意
Annotation[] sAnno2 = AnnotationUtils.getAnnotations(anno1.annotationType());
System.out.println(sAnno1);
System.out.println(sAnno2);
}
public static Annotation[] getAnnotations(Method method)
:支持桥接public static <A extends Annotation> Set<A> getRepeatableAnnotations(AnnotatedElement annotatedElement, Class<A> annotationType)
:支持了Java8的重复注解getDeclaredRepeatableAnnotations
(重载方法略):不解释public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType)
:他的特点就是,会递归去你的父类、接口里把注解找到,找到既返回
,返回第一个匹配的注解信息 顺序是:先接口后父类public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType)
:(其它重载方法略)@MyAnno
interface Eat {
}
class Parent implements Eat {
}
//本来,接口上的注解我们无论如何都继承不了了,但用了Spring的,你就可以
public static void main(String[] args) {
MyAnno annotation = AnnotationUtils.findAnnotation(Child.class, MyAnno.class);
System.out.println(annotation);
}
//备注:哪怕@MyAnno上没有标注@Inherited,也是能找出来的(这是后面讲解@RequestMapping为何能被子类继承的重要原因)
public static Class<?> findAnnotationDeclaringClass(Class<? extends Annotation> annotationType, @Nullable Class<?> clazz)
:找到第一个(自己有就自己了,否则去父类继续找)有这个注解的。Class~~(有可能是自己,有可能是父类) 备注:接口不找 public static void main(String[] args) {
Class<?> annotationDeclaringClass = AnnotationUtils.findAnnotationDeclaringClass(MyAnno.class, Child.class);
System.out.println(annotationDeclaringClass);
}
public static Class<?> findAnnotationDeclaringClassForTypes(List<Class<? extends Annotation>> annotationTypes, @Nullable Class<?> clazz)
:annotationTypes和上面相比,只有类里面有一个这个注解,就return了public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> annotationType, Class<?> clazz)
:简单的说就是自己本身Class是否含有指定的这个注解public static boolean isAnnotationInherited(Class<? extends Annotation> annotationType, Class<?> clazz)
:判断该Class上指定的注解是否是继承过来的。 public static void main(String[] args) {
System.out.println(AnnotationUtils.isAnnotationInherited(MyAnno.class, Parent.class)); //false
// 说明一下:clazz.isAnnotationPresent(annotationType) JDK的。表示注解存在就行,不管你是自己的还是继承来的
System.out.println(AnnotationUtils.isAnnotationInherited(MyAnno.class, Child.class)); //true 很显然,Child的这个注解是继承来的
// Child的MyAnno注解是父类的,但这里还是会返回true
System.out.println(Child.class.isAnnotationPresent(MyAnno.class)); //true
System.out.println(Child.class.getAnnotation(MyAnno.class)); // @com.fsx.maintest.MyAnno(c...
}
public static boolean isAnnotationMetaPresent(Class<? extends Annotation> annotationType, @Nullable Class<? extends Annotation> metaAnnotationType)
:简单的说:就是annotationType这个注解类型上面,是否标注有metaAnnotationType这个类型的注解 public static void main(String[] args) {
System.out.println(AnnotationUtils.isAnnotationMetaPresent(MyAnno.class, RequestMapping.class)); //true
System.out.println(AnnotationUtils.isAnnotationMetaPresent(MyAnno.class, Component.class)); //false
}
public static boolean isInJavaLangAnnotationPackage(@Nullable Annotation annotation)
:是否是JDK的注解(String的重载方法,省略) public static void main(String[] args) {
MyAnno myAnno = Eat.class.getAnnotation(MyAnno.class);
Target target = MyAnno.class.getAnnotation(Target.class);
System.out.println(AnnotationUtils.isInJavaLangAnnotationPackage(myAnno)); //false
System.out.println(AnnotationUtils.isInJavaLangAnnotationPackage(target)); //true
}
public static Map<String, Object> getAnnotationAttributes(Annotation annotation)
:获取这个注解的所有属性值们,用map保存(非常重要)public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap)
:最全的一个方法 classValuesAsString:true表示把Class类型的都转换为String类型,nestedAnnotationsAsMap:true表示连内嵌的注解也解析出来(默认都是false的) 注意此处返回的是AnnotationAttributes,它其实就是个Map
,提供了各种更便捷的获取方法:getString、getBoolean
等等public static AnnotationAttributes getAnnotationAttributes(@Nullable AnnotatedElement annotatedElement, Annotation annotation)
:annotatedElement表示被标注了后面这个注解的元素,如果不知道,你就传null吧// 给注解增加属性、有Class属性 也有嵌套属性
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping
@Inherited
@interface MyAnno {
String value() default "this is mine";
Class<? extends Number> clazz() default Integer.class;
// 注解类型的属性
Component anno() default @Component;
}
public static void main(String[] args) {
MyAnno myAnno = Eat.class.getAnnotation(MyAnno.class);
// 它原理是调用了下面的底层方法 传值为两个false
Map<String, Object> myAnnoAttrs = AnnotationUtils.getAnnotationAttributes(myAnno);
// 此处可以看到clazz输出的是class类型,并不是字符串。anno也是调用了toString方法,并没有解析内嵌的
System.out.println(myAnnoAttrs); //{clazz=class java.lang.Integer, value=this is mine, anno=@org.springframework.stereotype.Component(value=mytest)}
// =====传双true
AnnotationAttributes annotationAttributes = AnnotationUtils.getAnnotationAttributes(myAnno, true, true);
System.out.println(annotationAttributes); //{clazz=java.lang.Integer, value=this is mine, anno={value=mytest}}
// 经过我测试,第一个参数写Object.class都无所谓 结果和上面一样的
// 若哪位小伙伴知道这个参数有不同的解释,请告知哈
AnnotationAttributes classAnno = AnnotationUtils.getAnnotationAttributes(Object.class, myAnno, true, true);
System.out.println(classAnno);
}
public static Object getValue(Annotation annotation)
:获取注解内指定属性的值 public static void main(String[] args) {
MyAnno myAnno = Eat.class.getAnnotation(MyAnno.class);
// 个人觉得还不如直接:myAnno.value()呢 哈哈(Spring底层用的Method做的)
System.out.println(AnnotationUtils.getValue(myAnno)); //this is mine
System.out.println(AnnotationUtils.getValue(myAnno, "clazz")); //class java.lang.Integer
System.out.println(AnnotationUtils.getValue(myAnno, "aaa")); //null
}
public static Object getDefaultValue(@Nullable Annotation annotation, @Nullable String attributeName)
:和上面相比,这里只拿默认值。若没有设置默认值,那就返回nullpublic static <A extends Annotation> A synthesizeAnnotation(A annotation, @Nullable AnnotatedElement annotatedElement)
:提供出一个public的方法,外部也能调用代理指定的注解了(各种重载方法略)public static void clearCache()
:我们也可以手动调用此方法,清除内部的缓存顺便提一句,其内部有一个私有的静态内部类private static class AliasDescriptor
:专程用来处理@AliasFor
注解
AnnotatedElementUtils
:在AnnotatedElement
finding annotations, meta-annotations, and repeatable annotations(@since 4.0
)public static AnnotatedElement forAnnotations(final Annotation... annotations)
:给这么多的Annos提供一个适配器(内部就是new了一个AnnotatedElement
匿名内部类,没啥特殊的)public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, String annotationName)
:简单的说,就是返回指定Class上面这个注解上的注解
(若没有,返回null) 备注:不包含Java的元注解哦~public static boolean hasMetaAnnotationTypes(AnnotatedElement element, Class<? extends Annotation> annotationType)
:public static boolean isAnnotated(AnnotatedElement element, Class<? extends Annotation> annotationType)
:厉害。不管是注解,还是有注解的注解标注了 都返回true public static void main(String[] args) {
Set<String> metaAnnotationTypes = AnnotatedElementUtils.getMetaAnnotationTypes(Child.class, MyAnno.class);
System.out.println(metaAnnotationTypes); //[org.springframework.web.bind.annotation.RequestMapping, org.springframework.web.bind.annotation.Mapping]
// 请注意此处:因为是元注解types,所以第一个是false,第二个是true
System.out.println(AnnotatedElementUtils.hasMetaAnnotationTypes(Child.class, MyAnno.class)); // false
System.out.println(AnnotatedElementUtils.hasMetaAnnotationTypes(Child.class, RequestMapping.class)); // true
// 注意此处 两个都是true哦~~~
System.out.println(AnnotatedElementUtils.isAnnotated(Child.class, MyAnno.class)); // true
System.out.println(AnnotatedElementUtils.isAnnotated(Child.class, RequestMapping.class)); //true
}
@AliasFor
的时候再详说吧它在org.springframework.beans.annotation
包下,并且这个包下只有它一个类。该类只有一个核心方法。
public abstract class AnnotationBeanUtils {
// excludedProperties 排除的属性值不拷贝
public static void copyPropertiesToBean(Annotation ann, Object bean, String... excludedProperties) {
copyPropertiesToBean(ann, bean, null, excludedProperties);
}
public static void copyPropertiesToBean(Annotation ann, Object bean, @Nullable StringValueResolver valueResolver, String... excludedProperties) {
// 用set去重
Set<String> excluded = new HashSet<>(Arrays.asList(excludedProperties));
// 这是拿到该注解的所有属性(编译后都是通过method的方式存储的)
Method[] annotationProperties = ann.annotationType().getDeclaredMethods();
// 吧这个Bean包装成一个BeanWrapper
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(bean);
for (Method annotationProperty : annotationProperties) {
String propertyName = annotationProperty.getName();
if (!excluded.contains(propertyName) && bw.isWritableProperty(propertyName)) {
// 拿到注解的值
Object value = ReflectionUtils.invokeMethod(annotationProperty, ann);
// 若是字符串类型,还可以处理(也就值支持到了{}这种占位符形式)
if (valueResolver != null && value instanceof String) {
value = valueResolver.resolveStringValue((String) value);
}
// 把该Value值设置进去
bw.setPropertyValue(propertyName, value);
}
}
}
}
备注:这个我们一般用不着,Spring内在JMX相关类中使用。比如AnnotationJmxAttributeSource
AnnotationConfigUtils
是一个Spring
内部工具类,用于识别注解配置类中的bean定义。(和Bean注册有关)
public class AnnotationConfigUtils {
// 这个常量在我们AnnotationConfigApplicationContext#setBeanNameGenerator的时候会执行这么一句话:
//getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator)
// 然后在处理@Configuration里的@Bean的时候,会get出来处理名字
public static final String CONFIGURATION_BEAN_NAME_GENERATOR =
"org.springframework.context.annotation.internalConfigurationBeanNameGenerator";
//============= Spring默认会注册进去的7个Bean(若没导包,有可能是5个哦) ===========================
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalAutowiredAnnotationProcessor";
public static final String REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalRequiredAnnotationProcessor";
public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalCommonAnnotationProcessor";
public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalPersistenceAnnotationProcessor";
public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
"org.springframework.context.event.internalEventListenerProcessor";
public static final String EVENT_LISTENER_FACTORY_BEAN_NAME =
"org.springframework.context.event.internalEventListenerFactory";
private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME =
"org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";
private static final boolean jsr250Present =
ClassUtils.isPresent("javax.annotation.Resource", AnnotationConfigUtils.class.getClassLoader());
private static final boolean jpaPresent =
ClassUtils.isPresent("javax.persistence.EntityManagerFactory", AnnotationConfigUtils.class.getClassLoader()) &&
ClassUtils.isPresent(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader());
}
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source)
:该方法主要是向容器注册了一组基础设施PostProcessor bean
定义,这些bean定义生成的PostProcessor
实例被框架自己用于识别注解配置类中的bean定义(就是我们上面说的7大默认Bean定义,role均为:BeanDefinition.ROLE_INFRASTRUCTURE
表示框架自己用的)。 它还为Bean工厂设置了:setDependencyComparator
和setAutowireCandidateResolver
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd)
:处理通用的Bean定义上的注解,该方法从原始bean定义的元数据中获取那些通用的注解信息:@Lazy,@DependsOn,@Role,@Description
,然后设置AnnotatedBeanDefinition实例相应的属性基本上这个工具类是Spring内部使用的,我们用不着。它在
org.springframework.context.annotation
包内
ConfigurationClassUtils
:Spring内部处理@Configuration
的工具类这个工具类只处理@Configuration配置类的。是Full模式还是Lite模式
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
return metadata.isAnnotated(Configuration.class.getName());
}
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata){
//有@Component、@Component、@Import、@ImportResource标注的
// 或者类内部有@Bean标注的方法 都属于Lite模式的配置类
...
}
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
}
/////////////////////////////////////////////////////////
public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
}
public static boolean isLiteConfigurationClass(BeanDefinition beanDef) {
return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
}
// 获取@Order的值 since Spring5.0
@Nullable
public static Integer getOrder(AnnotationMetadata metadata) {
Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName());
return (orderAttributes != null ? ((Integer) orderAttributes.get(AnnotationUtils.VALUE)) : null);
}
// since Spring4.2
public static int getOrder(BeanDefinition beanDef) {
Integer order = (Integer) beanDef.getAttribute(ORDER_ATTRIBUTE);
return (order != null ? order : Ordered.LOWEST_PRECEDENCE);
}
javax.annotation.Priority
public abstract class OrderUtils {
@Nullable
public static Integer getOrder(Class<?> type) {
Order order = AnnotationUtils.findAnnotation(type, Order.class);
if (order != null) {
return order.value();
}
// 兼容到了JDK6提供的javax.annotation.Priority这个注解(需要额外导包)
Integer priorityOrder = getPriority(type);
if (priorityOrder != null) {
return priorityOrder;
}
return null;
}
@Nullable
public static Integer getPriority(Class<?> type) {
if (priorityAnnotationType != null) {
Annotation priority = AnnotationUtils.findAnnotation(type, priorityAnnotationType);
if (priority != null) {
return (Integer) AnnotationUtils.getValue(priority);
}
}
return null;
}
// 最常调用的还是下列方法:
public static int getOrder(Class<?> type, int defaultOrder) {
Integer order = getOrder(type);
return (order != null ? order : defaultOrder);
}
@Nullable
public static Integer getOrder(Class<?> type, @Nullable Integer defaultOrder) {
Integer order = getOrder(type);
return (order != null ? order : defaultOrder);
}
}
@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的方法(包含了父容器,默认实现都是不去父容器里找的)
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
类
它的获取一般这么来:
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易学难精是得以与他优秀的设计:分层、封装、扩展、包访问权限管理等等,在各处都有所体现