小言_互联网的博客

spring core:@AliasFor的派生性

216人阅读  评论(0)

spring对Annotation的派生性应用可谓炉火纯青,在spring core:@Component的派生性讲过支持层次上派生性,而属性上派生的需求则借助了@AliasFor,它是从spring4.2中开始支持的。

@AliasFor注解用于声明注解元素的别名,应用于方法上(别忘了注解本质是接口)。Spring框架在内部使用大量的使用这个注解,例如,@Bean@ComponentScan@Scope等。


  
  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(ElementType.METHOD)
  3. @Documented
  4. public @interface AliasFor {
  5. /**
  6. * * 引用的注解别名..
  7. */
  8. @AliasFor( "attribute")
  9. String value() default "";
  10. /**
  11. * 引用的注解别名.
  12. * @see #value
  13. */
  14. @AliasFor( "value")
  15. String attribute() default "";
  16. /**层次结构的父注解
  17. */
  18. Class<? extends Annotation> annotation() default Annotation.class;
  19. }

示例1

可通过AnnotatedElementUtils#getMergedAnnotationAttributes来读取。下面演示没有派生性的情况:


  
  1. @Test
  2. public void metaTest() throws IOException {
  3. AnnotationAttributes aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home.class, AccessRole.class);
  4. System.out.println(aa); //{value=super-user, module=gui, accessType=super-user}
  5. }
  6. @Target(ElementType.TYPE)
  7. @Retention(RetentionPolicy.RUNTIME)
  8. public @interface AccessRole {
  9. @AliasFor( "accessType")
  10. String value() default "visitor";
  11. @AliasFor( "value")
  12. String accessType() default "visitor";
  13. String module() default "gui";
  14. }
  15. @AccessRole( "super-user")
  16. //@AccessRole(value = "super-user",accessType = "super")//error
  17. public class Home {
  18. }

注:alias references的默认值必须一致,使用时指定值也必须一致,否则会抛出AnnotationConfigurationException

下面演示有单层次及多层次派生性的情况:


  
  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @AccessRole( "admin")
  4. public @interface AdminAccess {
  5. @AliasFor(annotation = AccessRole.class, attribute = "module")
  6. String value() default "service";
  7. }
  8. @AdminAccess
  9. public class Home2 {
  10. }
  11. @Target(ElementType.TYPE)
  12. @Retention(RetentionPolicy.RUNTIME)
  13. @AdminAccess( "supper")
  14. public @interface SupperAccess {
  15. String value() default "service3";
  16. @AliasFor(annotation = AccessRole.class, attribute = "module")
  17. String module() default "service3";
  18. }
  19. @SupperAccess
  20. public class Home3 {
  21. }
  22. @Test
  23. public void metaTest() throws IOException {
  24. AnnotationAttributes aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home2.class, AdminAccess.class);
  25. System.out.println(aa); //{value=service}
  26. aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home2.class, AccessRole.class);
  27. System.out.println(aa); //{value=admin, accessType=admin, module=service}
  28. aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home3.class, AccessRole.class);
  29. System.out.println(aa); //{value=admin, module=service3, accessType=admin}
  30. }

原理

AnnotatedElementUtils处理也不是特别复杂,很好理解


  
  1. public abstract class AnnotatedElementUtils {
  2. @Nullable
  3. public static AnnotationAttributes getMergedAnnotationAttributes(
  4. AnnotatedElement element, Class<? extends Annotation> annotationType) {
  5. AnnotationAttributes attributes = searchWithGetSemantics(element, annotationType, null,
  6. new MergedAnnotationAttributesProcessor());
  7. AnnotationUtils.postProcessAnnotationAttributes(element, attributes, false, false);
  8. return attributes;
  9. }
  10. //第一步:searchWithGetSemantics真正调用的方法,递归获取所有的注解
  11. @Nullable
  12. private static <T> T searchWithGetSemantics(AnnotatedElement element,
  13. Set<Class<? extends Annotation>> annotationTypes, @Nullable String annotationName,
  14. @Nullable Class<? extends Annotation> containerType, Processor<T> processor,
  15. Set<AnnotatedElement> visited, int metaDepth) {
  16. if (visited.add(element)) {
  17. try {
  18. // Start searching within locally declared annotations
  19. List<Annotation> declaredAnnotations = Arrays.asList(AnnotationUtils.getDeclaredAnnotations(element));
  20. T result = searchWithGetSemanticsInAnnotations(element, declaredAnnotations,
  21. annotationTypes, annotationName, containerType, processor, visited, metaDepth);
  22. if (result != null) {
  23. return result;
  24. }
  25. if (element instanceof Class) { // otherwise getAnnotations doesn't return anything new
  26. Class<?> superclass = ((Class<?>) element).getSuperclass();
  27. if (superclass != null && superclass != Object.class) {
  28. List<Annotation> inheritedAnnotations = new LinkedList<>();
  29. for (Annotation annotation : element.getAnnotations()) {
  30. if (!declaredAnnotations.contains(annotation)) {
  31. inheritedAnnotations.add(annotation);
  32. }
  33. }
  34. // Continue searching within inherited annotations
  35. result = searchWithGetSemanticsInAnnotations(element, inheritedAnnotations,
  36. annotationTypes, annotationName, containerType, processor, visited, metaDepth);
  37. if (result != null) {
  38. return result;
  39. }
  40. }
  41. }
  42. }
  43. catch (Throwable ex) {
  44. AnnotationUtils.handleIntrospectionFailure(element, ex);
  45. }
  46. }
  47. return null;
  48. }
  49. }
  50. public abstract class AnnotationUtils {
  51. //第二步:获取@AliasFor的标记,处理其值
  52. static void postProcessAnnotationAttributes(@Nullable Object annotatedElement,
  53. @Nullable AnnotationAttributes attributes, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
  54. if (attributes == null) {
  55. return;
  56. }
  57. Class<? extends Annotation> annotationType = attributes.annotationType();
  58. // Track which attribute values have already been replaced so that we can short
  59. // circuit the search algorithms.
  60. Set<String> valuesAlreadyReplaced = new HashSet<>();
  61. if (!attributes.validated) {
  62. // Validate @AliasFor configuration
  63. Map<String, List<String>> aliasMap = getAttributeAliasMap(annotationType);
  64. aliasMap.forEach((attributeName, aliasedAttributeNames) -> {
  65. if (valuesAlreadyReplaced.contains(attributeName)) {
  66. return;
  67. }
  68. Object value = attributes.get(attributeName);
  69. boolean valuePresent = (value != null && !(value instanceof DefaultValueHolder));
  70. for (String aliasedAttributeName : aliasedAttributeNames) {
  71. if (valuesAlreadyReplaced.contains(aliasedAttributeName)) {
  72. continue;
  73. }
  74. Object aliasedValue = attributes.get(aliasedAttributeName);
  75. boolean aliasPresent = (aliasedValue != null && !(aliasedValue instanceof DefaultValueHolder));
  76. // Something to validate or replace with an alias?
  77. if (valuePresent || aliasPresent) {
  78. if (valuePresent && aliasPresent) {
  79. // Since annotation attributes can be arrays, we must use ObjectUtils.nullSafeEquals().
  80. if (!ObjectUtils.nullSafeEquals(value, aliasedValue)) {
  81. String elementAsString =
  82. (annotatedElement != null ? annotatedElement.toString() : "unknown element");
  83. throw new AnnotationConfigurationException(String.format(
  84. "In AnnotationAttributes for annotation [%s] declared on %s, " +
  85. "attribute '%s' and its alias '%s' are declared with values of [%s] and [%s], " +
  86. "but only one is permitted.", attributes.displayName, elementAsString,
  87. attributeName, aliasedAttributeName, ObjectUtils.nullSafeToString(value),
  88. ObjectUtils.nullSafeToString(aliasedValue)));
  89. }
  90. }
  91. else if (aliasPresent) {
  92. // Replace value with aliasedValue
  93. attributes.put(attributeName,
  94. adaptValue(annotatedElement, aliasedValue, classValuesAsString, nestedAnnotationsAsMap));
  95. valuesAlreadyReplaced.add(attributeName);
  96. }
  97. else {
  98. // Replace aliasedValue with value
  99. attributes.put(aliasedAttributeName,
  100. adaptValue(annotatedElement, value, classValuesAsString, nestedAnnotationsAsMap));
  101. valuesAlreadyReplaced.add(aliasedAttributeName);
  102. }
  103. }
  104. }
  105. });
  106. attributes.validated = true;
  107. }
  108. // Replace any remaining placeholders with actual default values
  109. for (Map.Entry<String, Object> attributeEntry : attributes.entrySet()) {
  110. String attributeName = attributeEntry.getKey();
  111. if (valuesAlreadyReplaced.contains(attributeName)) {
  112. continue;
  113. }
  114. Object value = attributeEntry.getValue();
  115. if (value instanceof DefaultValueHolder) {
  116. value = ((DefaultValueHolder) value).defaultValue;
  117. attributes.put(attributeName,
  118. adaptValue(annotatedElement, value, classValuesAsString, nestedAnnotationsAsMap));
  119. }
  120. }
  121. }
  122. }

待续


转载:https://blog.csdn.net/itsoftchenfei/article/details/103787806
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场