在研究Spring源码关于注解解析时,发现有源码中有很大的篇幅在处理关于AliasFor标签。我在网上找了一下,发现Spring中的@AliasFor标签 这篇博客对@AliasFor的使用己经介绍得很详细了,只是对源码的具体处理方面,我觉得,如果不是研究过源码的同学,可能还是觉得镜花水月,因此,今天,对其中的一个具体的示例做一下分析,希望对大家有用,先上示例吧
AliasFor.java
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface AliasFor { @AliasFor("attribute") String value() default ""; @AliasFor("value") String attribute() default ""; Class<? extends Annotation> annotation() default Annotation.class; }
我们简单来看看@AliasFor标签的使用原理;
可以看到,@AliasFor标签自己就使用了自己,为value属性添加了attribute属性作为别名;
ParentMyAnnotation.java
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented public @interface ParentMyAnnotation { @AliasFor(value = "bbbb") String aaaa() default ""; @AliasFor(value = "aaaa") String bbbb() default ""; }
MyAnnotation.java
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @ParentMyAnnotation public @interface MyAnnotation { @AliasFor(attribute = "aaaa", annotation = ParentMyAnnotation.class) String xxxx() default ""; @AliasFor(attribute = "bbbb", annotation = ParentMyAnnotation.class) //缺省指明继承的父注解的中的属性名称,则默认继承父注解中同名的属性名 String yyyy() default ""; @AliasFor(attribute = "bbbb", annotation = ParentMyAnnotation.class) //缺省指明继承的父注解的中的属性名称,则默认继承父注解中同名的属性名 String zzzz() default ""; }
SubMyAnnotation.java
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @MyAnnotation public @interface SubMyAnnotation { @AliasFor(annotation = ParentMyAnnotation.class,attribute = "aaaa") String iiii() default ""; @AliasFor(annotation = MyAnnotation.class, attribute = "zzzz") String jjjj() default ""; }
GrandsonMyAnnotation.java
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @SubMyAnnotation public @interface GrandsonMyAnnotation { @AliasFor(annotation = MyAnnotation.class,attribute = "zzzz") String mmmm() default ""; @AliasFor(annotation = SubMyAnnotation.class, attribute = "iiii") String nnnn() default ""; }
定义三个注解类 ParentMyAnnotation,MyAnnotation,SubMyAnnotation,他们之间的关系是SubMyAnnotation继承MyAnnotation,MyAnnotation继承ParentMyAnnotation,GrandsonMyAnnotation 继承SubMyAnnotation。
MyAliasClass.java
@SubMyAnnotation(iiii = "11111111111") public class MyAliasClass { }
今天我们要测试的是,别名的传递,因为这个也是解析最为复杂的形式
@AliasFor注解是允许别名之间的传递的,简单理解,如果A是B的别名,并且B是C的别名,那么A是C的别名;
测试:
@Test public void test2() { MyAliasClass aliasTest = new MyAliasClass(); MyAnnotation myAnnotation = AnnotationUtils.getAnnotation(aliasTest.getClass(), MyAnnotation.class); System.out.println("xxxx:" + myAnnotation.xxxx() + ";yyyy:" + myAnnotation.yyyy()); }
结果:
为什么SubMyAnnotation中的属性iiii,和jjjj相等呢?那我们来直接进入源码分析吧
AnnotationUtils.java
public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) { try { //获取当前类的注解,这里主要是获取到interface com.spring_1_100.test_61_70.test64_1.SubMyAnnotation 的注解 A annotation = annotatedElement.getAnnotation(annotationType); if (annotation == null) { for (Annotation metaAnn : annotatedElement.getAnnotations()) { annotation = metaAnn.annotationType().getAnnotation(annotationType); if (annotation != null) { break; } } } //获取合成注解,可能返回的是一个代理类 return synthesizeAnnotation(annotation, annotatedElement); } catch (Exception ex) { handleIntrospectionFailure(annotatedElement, ex); } return null; } public static <A extends Annotation> A synthesizeAnnotation(A annotation, AnnotatedElement annotatedElement) { //注解为空,直接返回 if (annotation == null) { return null; } //如果是合成注解,直接返回 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); A synthesizedAnnotation = (A) Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), new Class<?>[] {(Class<A>) annotationType, SynthesizedAnnotation.class}, handler); return synthesizedAnnotation; } //从缓存中获取的情况,我们不考虑,只分析没有缓存的情况 private static boolean isSynthesizable(Class<? extends Annotation> annotationType) { Boolean synthesizable = synthesizableCache.get(annotationType); if (synthesizable != null) { return synthesizable.booleanValue(); } synthesizable = Boolean.FALSE; for (Method attribute : getAttributeMethods(annotationType)) { //获取当前注解的别名,如果别名不为空,则表示是可合并属性 if (!getAttributeAliasNames(attribute).isEmpty()) { synthesizable = Boolean.TRUE; break; } Class<?> returnType = attribute.getReturnType(); if (Annotation[].class.isAssignableFrom(returnType)) { Class<? extends Annotation> nestedAnnotationType = (Class<? extends Annotation>) returnType.getComponentType(); if (isSynthesizable(nestedAnnotationType)) { synthesizable = Boolean.TRUE; break; } } else if (Annotation.class.isAssignableFrom(returnType)) { Class<? extends Annotation> nestedAnnotationType = (Class<? extends Annotation>) returnType; if (isSynthesizable(nestedAnnotationType)) { synthesizable = Boolean.TRUE; break; } } } synthesizableCache.put(annotationType, synthesizable); return synthesizable.booleanValue(); } static List<Method> getAttributeMethods(Class<? extends Annotation> annotationType) { List<Method> methods = attributeMethodsCache.get(annotationType); if (methods != null) { return methods; } methods = new ArrayList<Method>(); //遍历注解所有的属性方法,将注解属性方法参数个数为0,并且返回值不为void类型的保存到methods中,并返回 for (Method method : annotationType.getDeclaredMethods()) { if (isAttributeMethod(method)) { ReflectionUtils.makeAccessible(method); methods.add(method); } } attributeMethodsCache.put(annotationType, methods); return methods; } static List<String> getAttributeAliasNames(Method attribute) { Assert.notNull(attribute, "attribute must not be null"); AliasDescriptor descriptor = AliasDescriptor.from(attribute); return (descriptor == null ? Collections.<String> emptyList() : descriptor.getAttributeAliasNames()); }
AliasDescriptor.java
public static AliasDescriptor from(Method attribute) { AliasDescriptor descriptor = aliasDescriptorCache.get(attribute); if (descriptor != null) { return descriptor; } //注解的属性方法中是否配置了@AliasFor注解 AliasFor aliasFor = attribute.getAnnotation(AliasFor.class); if (aliasFor == null) { return null; } descriptor = new AliasDescriptor(attribute, aliasFor); descriptor.validate(); aliasDescriptorCache.put(attribute, descriptor); return descriptor; } private AliasDescriptor(Method sourceAttribute, AliasFor aliasFor) { // 注解类 Class<?> declaringClass = sourceAttribute.getDeclaringClass(); Assert.isTrue(declaringClass.isAnnotation(), "sourceAttribute must be from an annotation"); // 源注解属性 this.sourceAttribute = sourceAttribute; // 注解类 this.sourceAnnotationType = (Class<? extends Annotation>) declaringClass; // 源注解属性名称 this.sourceAttributeName = this.sourceAttribute.getName(); //如果注解属性没有配置annotation,则别名注解类型是当前注解类 //如果如果注解属性配置了annotation,则别名注解类型是配置的注解类型 this.aliasedAnnotationType = (Annotation.class.equals(aliasFor.annotation()) ? this.sourceAnnotationType : aliasFor.annotation()); //获取注解属性所配置的@aliasFor注解的attribute 属性值 ,或name属性值 // 而 attribute 和 name 有且只有一个不为空或空串的值,则取出来 // 比如 attribute = "aaa", name="bbb" 抛出异常 // 比如 attribute = "", name="" 抛出异常 // 比如 attribute = "zzzz", name="" 或 attribute = "", name="bbb" ,不会抛出异常,并返回zzzz或bbb this.aliasedAttributeName = getAliasedAttributeName(aliasFor, this.sourceAttribute); try { // 这个不好理解,我们举个例子吧 配置如下 // @AliasFor(annotation = MyAnnotation.class, attribute = "zzzz") // String jjjj() default ""; // sourceAttribute :public abstract java.lang.String com.spring_1_100.test_61_70.test64_1.SubMyAnnotation.jjjj() // sourceAnnotationType :interface com.spring_1_100.test_61_70.test64_1.SubMyAnnotation // aliasedAnnotationType :interface com.spring_1_100.test_61_70.test64_1.MyAnnotation // 得到 aliasedAttribute :public abstract java.lang.String com.spring_1_100.test_61_70.test64_1.MyAnnotation.zzzz() // 假如:@MyAnnotation注解中没有zzzz属性,将抛出下面异常 this.aliasedAttribute = this.aliasedAnnotationType.getDeclaredMethod(this.aliasedAttributeName); } catch (NoSuchMethodException ex) { String msg = String.format( "Attribute [%s] in annotation [%s] is declared as an @AliasFor nonexistent attribute [%s] in annotation [%s].", this.sourceAttributeName, this.sourceAnnotationType.getName(), this.aliasedAttributeName, this.aliasedAnnotationType.getName()); throw new AnnotationConfigurationException(msg, ex); } //如果注解属性配置了@AliasFor 并且设置了annotation属性,isAliasPair为false,否则为true this.isAliasPair = this.sourceAnnotationType.equals(this.aliasedAnnotationType); } //进行验证 private void validate() { // 如果注解属性的注解@AliasFor配置了annotation,但是annotation 不是当前注解类的父类或者祖先类,抛出异常 // 如果annotation配置了是当前类的子类,比如在SubMyAnnotation的属性中配置了GrandsonMyAnnotation, // 而GrandsonMyAnnotation继承SubMyAnnotation,将抛出异常 if (!this.isAliasPair && !isAnnotationMetaPresent(this.sourceAnnotationType, this.aliasedAnnotationType)) { String msg = String.format("@AliasFor declaration on attribute [%s] in annotation [%s] declares " + "an alias for attribute [%s] in meta-annotation [%s] which is not meta-present.", this.sourceAttributeName, this.sourceAnnotationType.getName(), this.aliasedAttributeName, this.aliasedAnnotationType.getName()); throw new AnnotationConfigurationException(msg); } if (this.isAliasPair) { AliasFor mirrorAliasFor = this.aliasedAttribute.getAnnotation(AliasFor.class); if (mirrorAliasFor == null) { String msg = String.format( "Attribute [%s] in annotation [%s] must be declared as an @AliasFor [%s].", this.aliasedAttributeName, this.sourceAnnotationType.getName(), this.sourceAttributeName); throw new AnnotationConfigurationException(msg); } // 如果源属性和别名注解属性的值不相等,抛出异常 String mirrorAliasedAttributeName = getAliasedAttributeName(mirrorAliasFor, this.aliasedAttribute); if (!this.sourceAttributeName.equals(mirrorAliasedAttributeName)) { String msg = String.format( "Attribute [%s] in annotation [%s] must be declared as an @AliasFor [%s], not [%s].", this.aliasedAttributeName, this.sourceAnnotationType.getName(), this.sourceAttributeName, mirrorAliasedAttributeName); throw new AnnotationConfigurationException(msg); } } Class<?> returnType = this.sourceAttribute.getReturnType(); Class<?> aliasedReturnType = this.aliasedAttribute.getReturnType(); //如果源注解属性和别名注解属性返回值不相等,抛出异常 if (!returnType.equals(aliasedReturnType)) { String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " + "and attribute [%s] in annotation [%s] must declare the same return type.", this.sourceAttributeName, this.sourceAnnotationType.getName(), this.aliasedAttributeName, this.aliasedAnnotationType.getName()); throw new AnnotationConfigurationException(msg); } if (this.isAliasPair) { validateDefaultValueConfiguration(this.aliasedAttribute); } } private void validateDefaultValueConfiguration(Method aliasedAttribute) { Assert.notNull(aliasedAttribute, "aliasedAttribute must not be null"); Object defaultValue = this.sourceAttribute.getDefaultValue(); Object aliasedDefaultValue = aliasedAttribute.getDefaultValue(); //如果默认值为空,抛出异常 if (defaultValue == null || aliasedDefaultValue == null) { String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " + "and attribute [%s] in annotation [%s] must declare default values.", this.sourceAttributeName, this.sourceAnnotationType.getName(), aliasedAttribute.getName(), aliasedAttribute.getDeclaringClass().getName()); throw new AnnotationConfigurationException(msg); } //如果源注解属性和别名注解属性值默认值不相等,抛出异常 if (!ObjectUtils.nullSafeEquals(defaultValue, aliasedDefaultValue)) { String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " + "and attribute [%s] in annotation [%s] must declare the same default value.", this.sourceAttributeName, this.sourceAnnotationType.getName(), aliasedAttribute.getName(), aliasedAttribute.getDeclaringClass().getName()); throw new AnnotationConfigurationException(msg); } }
AnnotationUtils.java
public List<String> getAttributeAliasNames() { // Explicit alias pair? if (this.isAliasPair) { return Collections.singletonList(this.aliasedAttributeName); } // Else: search for implicit aliases List<String> aliases = new ArrayList<String>(); for (AliasDescriptor otherDescriptor : getOtherDescriptors()) { if (this.isAliasFor(otherDescriptor)) { //验证当前注解及otherDescriptor的默认值是否为空,任意一个为空,抛出异常,且如果不相等,抛出异常 this.validateAgainst(otherDescriptor); //将otherDescriptor注解的别名加入到aliases aliases.add(otherDescriptor.sourceAttributeName); } } return aliases; } private List<AliasDescriptor> getOtherDescriptors() { List<AliasDescriptor> otherDescriptors = new ArrayList<AliasDescriptor>(); for (Method currentAttribute : getAttributeMethods(this.sourceAnnotationType)) { //将非源注解的其他注解转化AliasDescriptor成加入到otherDescriptors中 if (!this.sourceAttribute.equals(currentAttribute)) { AliasDescriptor otherDescriptor = AliasDescriptor.from(currentAttribute); if (otherDescriptor != null) { otherDescriptors.add(otherDescriptor); } } } return otherDescriptors; } // 递归当前注解及别名注解与其他注解属性的注解及别名注解,两者看有没有相等的,如果有相等,则返回true private boolean isAliasFor(AliasDescriptor otherDescriptor) { for (AliasDescriptor lhs = this; lhs != null; lhs = lhs.getAttributeOverrideDescriptor()) { for (AliasDescriptor rhs = otherDescriptor; rhs != null; rhs = rhs.getAttributeOverrideDescriptor()) { if (lhs.aliasedAttribute.equals(rhs.aliasedAttribute)) { return true; } } } return false; } private AliasDescriptor getAttributeOverrideDescriptor() { //如果注解属性没有配置annotation if (this.isAliasPair) { return null; } //如果配置了annotation,则找当前注解属性的别名属性,转化为AliasDescriptor对象 return AliasDescriptor.from(this.aliasedAttribute); }
DefaultAnnotationAttributeExtractor.java
DefaultAnnotationAttributeExtractor(Annotation annotation, AnnotatedElement annotatedElement) { super(annotation.annotationType(), annotatedElement, annotation); }
AbstractAliasAwareAnnotationAttributeExtractor.java
AbstractAliasAwareAnnotationAttributeExtractor(Class<? extends Annotation> annotationType, AnnotatedElement annotatedElement, S source) { Assert.notNull(annotationType, "annotationType must not be null"); Assert.notNull(source, "source must not be null"); this.annotationType = annotationType; this.annotatedElement = annotatedElement; this.source = source; this.attributeAliasMap = AnnotationUtils.getAttributeAliasMap(annotationType); }
到这里终于将注解解析完成了,那么是如何获取iiii的值的呢?
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (isEqualsMethod(method)) { return annotationEquals(args[0]); } if (isHashCodeMethod(method)) { return annotationHashCode(); } if (isToStringMethod(method)) { return annotationToString(); } //方法的名称是annotationType,返回值为0 if (isAnnotationTypeMethod(method)) { return annotationType(); } //方法的参数个数为大于0或者方法返回值为void类型 if (!isAttributeMethod(method)) { String msg = String.format("Method [%s] is unsupported for synthesized annotation type [%s]", method, annotationType()); throw new AnnotationConfigurationException(msg); } return getAttributeValue(method); } private Object getAttributeValue(Method attributeMethod) { String attributeName = attributeMethod.getName(); Object value = this.valueCache.get(attributeName); if (value == null) { // 调用 DefaultAnnotationAttributeExtractor 的属性方法 value = this.attributeExtractor.getAttributeValue(attributeMethod); if (value == null) { throw new IllegalStateException(String.format( "%s returned null for attribute name [%s] from attribute source [%s]", this.attributeExtractor.getClass().getName(), attributeName, this.attributeExtractor.getSource())); } // Synthesize nested annotations before returning them. if (value instanceof Annotation) { value = synthesizeAnnotation((Annotation) value, this.attributeExtractor.getAnnotatedElement()); } else if (value instanceof Annotation[]) { value = synthesizeAnnotationArray((Annotation[]) value, this.attributeExtractor.getAnnotatedElement()); } this.valueCache.put(attributeName, value); } // Clone arrays so that users cannot alter the contents of values in our cache. if (value.getClass().isArray()) { value = cloneArray(value); } return value; }
AbstractAliasAwareAnnotationAttributeExtractor.java
public final Object getAttributeValue(Method attributeMethod) { //获取当前注解属性名称 final String attributeName = attributeMethod.getName(); //通过反射获取属性值 Object attributeValue = getRawAttributeValue(attributeMethod); //获取当前注解的所有别名 List<String> aliasNames = this.attributeAliasMap.get(attributeName); if (aliasNames != null) { //获取当前注解默认值 final Object defaultValue = AnnotationUtils.getDefaultValue(getAnnotationType(), attributeName); for (String aliasName : aliasNames) { //获取别名注释用户配置的值,如果用户没有配置,则使用默认值 Object aliasValue = getRawAttributeValue(aliasName); //如果 iiii="1111",jjjj="2222" 而iiii 的默认值为 "" ,抛出异常 //如果iiii="1111",jjjj="",默认值为"",不会抛出异常 if (!ObjectUtils.nullSafeEquals(attributeValue, aliasValue) && !ObjectUtils.nullSafeEquals(attributeValue, defaultValue) && !ObjectUtils.nullSafeEquals(aliasValue, defaultValue)) { String elementName = (getAnnotatedElement() != null ? getAnnotatedElement().toString() : "unknown element"); throw new AnnotationConfigurationException(String.format( "In annotation [%s] declared on %s and synthesized from [%s], attribute '%s' and its " + "alias '%s' are present with values of [%s] and [%s], but only one is permitted.", getAnnotationType().getName(), elementName, getSource(), attributeName, aliasName, ObjectUtils.nullSafeToString(attributeValue), ObjectUtils.nullSafeToString(aliasValue))); } // 如果iiii="",默认值为"",则使用别名属性值jjjj配置的值作为返回值 if (ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) { attributeValue = aliasValue; } } } return attributeValue; }
到这里,我们终于将Spring的注解属性解析讲完了。整个过程比较繁索,下面我们来总结一下
- 如果注解属性中没有配置了annotation,那么整个过程比较简单,只要看别名注解属性的默认值,和返回值,是不是相等,如果相等,则可以创建代理注解类,来获取注解属性值。
- 如果注解属性中配置了annotation,要看annotation配置类是不是当前注解属性所在类的子孙类,如果不在,则抛出异常。再检测注解属性和别名属性返回值是否相等,不相等,抛出异常。
- 获取注解属性的所有别名,如果别名不为空,则是创建代理注解处理器
- 通过代理获取注解属性。
Spring的每一个细节都非常的有意思,读者,有意向,还是自己下载代码,研究一下,使我们不仅仅停留在表示肤浅的理解注解。
本文的github地址是https://github.com/quyixiao/spring_tiny/tree/master/src/main/java/com/spring_1_100/test_61_70/test64_1