Spring注解(⼆)注解⼯具类
本⽂转载⾃
1.
⾸先回顾⼀下AnnotationUtils和AnnotatedElementUtils这两个注解⼯具类的⽤法:
@Test
@GetMapping(value = "/GetMapping", consumes = MediaType.APPLICATION_JSON_VALUE)
public void test() throws NoSuchMethodException {
Method method = ReflectUtils.findDeclaredMethod(
AliasForTest.class, "test", null);
// AnnotationUtils 不⽀持注解属性覆盖
RequestMapping requestMappingAnn1 = Annotation(method, RequestMapping.class);
Assert.assertEquals(new String[]{}, requestMappingAnn1.value());
Assert.assertEquals(new String[]{}, sumes());
// AnnotatedElementUtils ⽀持注解属性覆盖
RequestMapping requestMappingAnn2 = MergedAnnotation(method, RequestMapping.class);    Assert.assertEquals(new String[]{"/GetMapping"}, requestMappingAnn2.value());
Assert.assertEquals(new String[]{MediaType.APPLICATION_JSON_VALUE}, sumes());
}
源码分析
AnnotationUtils解决注解别名,包括显式别名、隐式别名、传递的隐式别名,还可以查的指定注解的属性信息。
AnnotationUtils底层使⽤动态代理的⽅式处理注解别名的问题。
get* 系列注解查
get 遵循 JDK 的注解查语义,只是增加了⼀级元注解的查。
public static <A extends Annotation> A getAnnotation(Annotation annotation, Class<A> annotationType) {
// 1. 直接查本地注解
if (annotationType.isInstance(annotation)) {
return synthesizeAnnotation((A) annotation);
}
// 2. 元注解上查,注意相对于 find* ⽽⾔,这⾥只查⼀级元注解
Class<? extends Annotation> annotatedElement = annotation.annotationType();
try {
A metaAnn = Annotation(annotationType);
return (metaAnn != null ? synthesizeAnnotation(metaAnn, annotatedElement) : null);
}
catch (Throwable ex) {
handleIntrospectionFailure(annotatedElement, ex);
return null;
}
}
find* 系列注解查
遵循 JDK 的注解查语义,只是增加了多级元注解的查。
// visited 表⽰已经查的元素,Spring 的递归很多都⽤到了这个参数
private static <A extends Annotation> A findAnnotation(
AnnotatedElement annotatedElement, Class<A> annotationType, Set<Annotation> visited) {
try {
// 1. 本地注解查
A annotation = DeclaredAnnotation(annotationType);
if (annotation != null) {
return annotation;
}
/
/ 2. 元注解上查
for (Annotation declaredAnn : getDeclaredAnnotations(annotatedElement)) {
Class<? extends Annotation> declaredType = declaredAnn.annotationType();
if (!isInJavaLangAnnotationPackage(declaredType) && visited.add(declaredAnn)) {
// 3. 元注解上递归查
annotation = findAnnotation((AnnotatedElement) declaredType, annotationType, visited);
if (annotation != null) {
return annotation;
}
}
}
}
catch (Throwable ex) {
handleIntrospectionFailure(annotatedElement, ex);
}
return null;
}
synthesizeAnnotation 动态代理解决别名问题
static <A extends Annotation> A synthesizeAnnotation(A annotation, @Nullable Object annotatedElement) {    // 1. SynthesizedAnnotation 为⼀个标记,表⽰已经动态代理过了
//    hasPlainJavaAnnotationsOnly 如果是 java 中的注解不可能有注解别名,直接返回
if (annotation instanceof SynthesizedAnnotation || hasPlainJavaAnnotationsOnly(annotatedElement)) {        return annotation;
}
// 2. 判断是否需要进⾏动态代理,即注解中存在别名,包括显⽰别名、隐式别名、传递的隐式别名
Class<? extends Annotation> annotationType = annotation.annotationType();
if (!isSynthesizable(annotationType)) {
return annotation;
}
// 3. AnnotationAttributeExtractor ⽤于从注解 annotation 中提取属性的值
DefaultAnnotationAttributeExtractor attributeExtractor =
new DefaultAnnotationAttributeExtractor(annotation, annotatedElement);
// 4. SynthesizedAnnotationInvocationHandler 动态代理的类
InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);
/
/ 5. 接⼝中有 SynthesizedAnnotation,并返回动态代理的对象
Class<?>[] exposedInterfaces = new Class<?>[] {annotationType, SynthesizedAnnotation.class};
return (A) Class().getClassLoader(), exposedInterfaces, handler); }
SynthesizedAnnotationInvocationHandler
下⾯主要看⼀下动态代理的 invoke 实现是怎么实现的。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (ReflectionUtils.isEqualsMethod(method)) {
return annotationEquals(args[0]);
}
if (ReflectionUtils.isHashCodeMethod(method)) {
return annotationHashCode();
}
if (ReflectionUtils.isToStringMethod(method)) {
return annotationToString();
}
// 注解的 annotationType 返回注解的 Class 类型
if (AnnotationUtils.isAnnotationTypeMethod(method)) {
return annotationType();
}
if (!AnnotationUtils.isAttributeMethod(method)) {
throw new AnnotationConfigurationException(String.format(
"Method [%s] is unsupported for synthesized annotation type [%s]", method, annotationType()));
}
// 真正获取注解的属性值
return getAttributeValue(method);
}
getAttributeValue 的核⼼其实就⼀句话AttributeValue(attributeMethod);委托给了对应的AnnotationAttributeExtractor 处理。
AnnotationAttributeExtractor
AbstractAliasAwareAnnotationAttributeExtractor(
Class<? extends Annotation> annotationType, @Nullable Object annotatedElement, S source) {
this.annotationType = annotationType;
this.annotatedElement = annotatedElement;
this.source = source;
this.attributeAliasMap = AttributeAliasMap(annotationType);
}
在构造⽅法中有⼀个很重要的⽅法 AttributeAliasMap(annotationType) ⽤于获取其别名。
public final Object getAttributeValue(Method attributeMethod) {
String attributeName = Name();
// attributeValue 表⽰属性的真实值
Object attributeValue = getRawAttributeValue(attributeMethod);
// 获取所有的别名
List<String> aliasNames = (attributeName);
if (aliasNames != null) {
// 属性的默认值,默认值肯定是⼀样的,因为在获取别名的时候已经校验了默认值
Object defaultValue = DefaultValue(this.annotationType, attributeName);
for (String aliasName : aliasNames) {
// 别名的真实值
Object aliasValue = getRawAttributeValue(aliasName);
// 如果两个别名的值不相等,且都不等于默认值,直接抛异常
if (!ObjectUtils.nullSafeEquals(attributeValue, aliasValue) &&
!ObjectUtils.nullSafeEquals(attributeValue, defaultValue) &&
!ObjectUtils.nullSafeEquals(aliasValue, defaultValue)) {
throw new AnnotationConfigurationException();
}
if (ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) {
attributeValue = aliasValue;
}
}
}
return attributeValue;
}
AliasDescriptor
getAttributeAliasMap
在 AbstractAliasAwareAnnotationAttributeExtractor 的构造器中有⼀个很重要的⽅法 getAttributeAliasMap 获取注解中所有属性的别名。
static Map<String, List<String>> getAttributeAliasMap(@Nullable Class<? extends Annotation> annotationType) {
map = new LinkedHashMap<>();
for (Method attribute : getAttributeMethods(annotationType)) {
List<String> aliasNames = getAttributeAliasNames(attribute);
if (!aliasNames.isEmpty()) {
map.Name(), aliasNames);
}
}
return map;
}
static List<String> getAttributeAliasNames(Method attribute) {
AliasDescriptor descriptor = AliasDescriptor.from(attribute);
return (descriptor != null ? AttributeAliasNames() : ptyList());
}
可以别名获取的所有的⼯作都是委托给了 AliasDescriptor 完成,这⼀⼩节我们就主要看⼀下这个类。
AliasDescriptor 构造及校验
public static AliasDescriptor from(Method attribute) {
AliasFor aliasFor = Annotation(AliasFor.class);
if (aliasFor == null) {
return null;
}
descriptor = new AliasDescriptor(attribute, aliasFor);
descriptor.validate();
return descriptor;
}
构建⼀个 AliasDescriptor 分为两步:⼀是获取注解信息(构造器),⼆是校验别名是否成⽴(validate)。@AliasFor 有以下的规约:
private AliasDescriptor(Method sourceAttribute, AliasFor aliasFor) {
Class<?> declaringClass = DeclaringClass();
// 1. 注解原字段的信息
this.sourceAttribute = sourceAttribute;
this.sourceAnnotationType = (Class<? extends Annotation>) declaringClass;
this.sourceAttributeName = Name();
// 2. @AliasFor 注解的信息
// 规约1:显⽰的别名可以不⽤配置 annotation 属性
// 规约2:隐式别名默认和原注解属性名称⼀致,getAliasedAttributeName 中体现
this.aliasedAnnotationType = (Annotation.class == aliasFor.annotation() ?
this.sourceAnnotationType : aliasFor.annotation());
this.aliasedAttributeName = getAliasedAttributeName(aliasFor, sourceAttribute);
if (this.aliasedAnnotationType == this.sourceAnnotationType &&
this.aliasedAttributeName.equals(this.sourceAttributeName)) {
throw new AnnotationConfigurationException(...);
}
try {
// @AliasFor 配置的别名不存在直接抛出异常
this.aliasedAttribute = DeclaredMethod(this.aliasedAttributeName);
} catch (NoSuchMethodException ex) {
throw new AnnotationConfigurationException(..., ex);
}
// 3. isAliasPair=true 表⽰就同⼀个注解内的显⽰别名
getattribute方法返回类型this.isAliasPair = (this.sourceAnnotationType == this.aliasedAnnotationType);
}
getAttributeAliasNames 获取别名
public List<String> getAttributeAliasNames() {
// 1. 显⽰别名,直接返回
if (this.isAliasPair) {
return Collections.singletonList(this.aliasedAttributeName);
}
// 2. 隐式别名,包括可传递的隐式别名
List<String> aliases = new ArrayList<>();
// 2.1 遍历注解中的其它属性,⼀⼀判断是否互为别名
//    getOtherDescriptors 获取其它的所有属性
//    isAliasFor 判断两个属性是否互为别名,会递归向上查
for (AliasDescriptor otherDescriptor : getOtherDescriptors()) {
if (this.isAliasFor(otherDescriptor)) {
this.validateAgainst(otherDescriptor);
aliases.add(otherDescriptor.sourceAttributeName);
}
}
return aliases;
}
getAttributeOverrideName 获取当前属性在元注解中对应的别名
public String getAttributeOverrideName(Class<? extends Annotation> metaAnnotationType) {
// 递归向上查别名,如果 sourceAnnotationType==metaAnnotationType 则查到了
for (AliasDescriptor desc = this; desc != null; desc = AttributeOverrideDescriptor()) {
if (desc.isOverrideFor(metaAnnotationType)) {
return desc.aliasedAttributeName;
}
}
return null;
}
源码分析
Processor 对匹配的注解进⾏后置处理
Processor 对匹配的注解进⾏后置处理,可以通过 process ⽅法的返回值来控制查的流程:返回 null 时继续查,⾮ null 时直接返回。有⼀种情况例外就是 aggregates=true,这种情况要查所有的注解,所以会继续查。
接⼝
private interface Processor<T> {
// 两个作⽤:⼀是根据返回值是否为 null 控制查询的流程;⼆是对查询的注解进⾏处理,主要是⽤于获取该注解的属性值
T process(@Nullable AnnotatedElement annotatedElement, Annotation annotation, int metaDepth);
// 只有 MergedAnnotationAttributesProcessor 有效,⽤于处理元注解属性覆盖
// annotation 为当前注解,result 为元注解属性信息,annotation 会覆盖元注解中的属性信息
void postProcess(@Nullable AnnotatedElement annotatedElement, Annotation annotation, T result);
// 查询所有元注解时有效,不管是否匹配都要执⾏ process ⽅法
boolean alwaysProcesses();
// MergedAnnotationAttributesProcessor 查所有的注解有效
boolean aggregates();
List<T> getAggregatedResults();
}
有两个⽅法要特别关注:
类图
Processor 的有⼏个实现:SimpleAnnotationProcessor 相当于⼀个简单的适配器;AlwaysTrueBoolean
AnnotationProcessor 的process ⽅法永远返回 TRUE;MergedAnnotationAttributesProcessor ⽤于处理元注解属性覆盖。
常⽤的⽅法对应的 Processor 返回值如下: