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

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AliasFor {
/**
* * 引用的注解别名..
*/
@AliasFor("attribute")
String value() default "";
/**
* 引用的注解别名.
* @see #value
*/
@AliasFor("value")
String attribute() default "";
/**层次结构的父注解
*/
Class<? extends Annotation> annotation() default Annotation.class;
}
示例1

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

@Test
public void metaTest() throws IOException {
AnnotationAttributes aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home.class, AccessRole.class);
System.out.println(aa);//{value=super-user, module=gui, accessType=super-user}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessRole {
@AliasFor("accessType")
String value() default "visitor";

@AliasFor("value")
String accessType() default "visitor";

String module() default "gui";
}
@AccessRole("super-user")
//@AccessRole(value = "super-user",accessType = "super")//error
public class Home {
}
注:alias references的默认值必须一致,使用时指定值也必须一致,否则会抛出AnnotationConfigurationException

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@AccessRole("admin")
public @interface AdminAccess {
@AliasFor(annotation = AccessRole.class, attribute = "module")
String value() default "service";
}
@AdminAccess
public class Home2 {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@AdminAccess("supper")
public @interface SupperAccess {
String value() default "service3";
@AliasFor(annotation = AccessRole.class, attribute = "module")
String module() default "service3";
}
@SupperAccess
public class Home3 {
}
@Test
public void metaTest() throws IOException {
AnnotationAttributes aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home2.class, AdminAccess.class);
System.out.println(aa);//{value=service}
aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home2.class, AccessRole.class);
System.out.println(aa);//{value=admin, accessType=admin, module=service}
aa = AnnotatedElementUtils.getMergedAnnotationAttributes(Home3.class, AccessRole.class);
System.out.println(aa);//{value=admin, module=service3, accessType=admin}
}
原理

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

public abstract class AnnotatedElementUtils {
@Nullable
public static AnnotationAttributes getMergedAnnotationAttributes(
AnnotatedElement element, Class<? extends Annotation> annotationType) {

AnnotationAttributes attributes = searchWithGetSemantics(element, annotationType, null,
new MergedAnnotationAttributesProcessor());
AnnotationUtils.postProcessAnnotationAttributes(element, attributes, false, false);
return attributes;
}
//第一步:searchWithGetSemantics真正调用的方法,递归获取所有的注解
@Nullable
private static <T> T searchWithGetSemantics(AnnotatedElement element,
Set<Class<? extends Annotation>> annotationTypes, @Nullable String annotationName,
@Nullable Class<? extends Annotation> containerType, Processor<T> processor,
Set<AnnotatedElement> visited, int metaDepth) {

if (visited.add(element)) {
try {
// Start searching within locally declared annotations
List<Annotation> declaredAnnotations = Arrays.asList(AnnotationUtils.getDeclaredAnnotations(element));
T result = searchWithGetSemanticsInAnnotations(element, declaredAnnotations,
annotationTypes, annotationName, containerType, processor, visited, metaDepth);
if (result != null) {
return result;
}

if (element instanceof Class) { // otherwise getAnnotations doesn't return anything new
Class<?> superclass = ((Class<?>) element).getSuperclass();
if (superclass != null && superclass != Object.class) {
List<Annotation> inheritedAnnotations = new LinkedList<>();
for (Annotation annotation : element.getAnnotations()) {
if (!declaredAnnotations.contains(annotation)) {
inheritedAnnotations.add(annotation);
}
}
// Continue searching within inherited annotations
result = searchWithGetSemanticsInAnnotations(element, inheritedAnnotations,
annotationTypes, annotationName, containerType, processor, visited, metaDepth);
if (result != null) {
return result;
}
}
}
}
catch (Throwable ex) {
AnnotationUtils.handleIntrospectionFailure(element, ex);
}
}

return null;
}
}
public abstract class AnnotationUtils {
//第二步:获取@AliasFor的标记,处理其值
static void postProcessAnnotationAttributes(@Nullable Object annotatedElement,
@Nullable AnnotationAttributes attributes, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {

if (attributes == null) {
return;
}

Class<? extends Annotation> annotationType = attributes.annotationType();

// Track which attribute values have already been replaced so that we can short
// circuit the search algorithms.
Set<String> valuesAlreadyReplaced = new HashSet<>();

if (!attributes.validated) {
// Validate @AliasFor configuration
Map<String, List<String>> aliasMap = getAttributeAliasMap(annotationType);
aliasMap.forEach((attributeName, aliasedAttributeNames) -> {
if (valuesAlreadyReplaced.contains(attributeName)) {
return;
}
Object value = attributes.get(attributeName);
boolean valuePresent = (value != null && !(value instanceof DefaultValueHolder));
for (String aliasedAttributeName : aliasedAttributeNames) {
if (valuesAlreadyReplaced.contains(aliasedAttributeName)) {
continue;
}
Object aliasedValue = attributes.get(aliasedAttributeName);
boolean aliasPresent = (aliasedValue != null && !(aliasedValue instanceof DefaultValueHolder));
// Something to validate or replace with an alias?
if (valuePresent || aliasPresent) {
if (valuePresent && aliasPresent) {
// Since annotation attributes can be arrays, we must use ObjectUtils.nullSafeEquals().
if (!ObjectUtils.nullSafeEquals(value, aliasedValue)) {
String elementAsString =
(annotatedElement != null ? annotatedElement.toString() : "unknown element");
throw new AnnotationConfigurationException(String.format(
"In AnnotationAttributes for annotation [%s] declared on %s, " +
"attribute '%s' and its alias '%s' are declared with values of [%s] and [%s], " +
"but only one is permitted.", attributes.displayName, elementAsString,
attributeName, aliasedAttributeName, ObjectUtils.nullSafeToString(value),
ObjectUtils.nullSafeToString(aliasedValue)));
}
}
else if (aliasPresent) {
// Replace value with aliasedValue
attributes.put(attributeName,
adaptValue(annotatedElement, aliasedValue, classValuesAsString, nestedAnnotationsAsMap));
valuesAlreadyReplaced.add(attributeName);
}
else {
// Replace aliasedValue with value
attributes.put(aliasedAttributeName,
adaptValue(annotatedElement, value, classValuesAsString, nestedAnnotationsAsMap));
valuesAlreadyReplaced.add(aliasedAttributeName);
}
}
}
});
attributes.validated = true;
}

// Replace any remaining placeholders with actual default values
for (Map.Entry<String, Object> attributeEntry : attributes.entrySet()) {
String attributeName = attributeEntry.getKey();
if (valuesAlreadyReplaced.contains(attributeName)) {
continue;
}
Object value = attributeEntry.getValue();
if (value instanceof DefaultValueHolder) {
value = ((DefaultValueHolder) value).defaultValue;
attributes.put(attributeName,
adaptValue(annotatedElement, value, classValuesAsString, nestedAnnotationsAsMap));
}
}
}
}
待续
————————————————
版权声明:本文为CSDN博主「布道」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/alex_xfboy/article/details/103787806

spring core:@AliasFor的派生性的更多相关文章

  1. 【Spring开发】—— Spring Core

    原文:[Spring开发]-- Spring Core 前言 最近由于一些工作的需要,还有自己知识的匮乏再次翻开spring.正好整理了一下相关的知识,弥补了之前对spring的一些错误认知.这一次学 ...

  2. vs2012+Spring.Core.dll

    Ⅰ.Spring的点点滴滴--序章   spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架 .net篇(环境为vs2012+Spring.Core.dll) 新建一个控制台 u ...

  3. spring core 与 context理解

    Spring core是核心层,拥有这BeanFactory这个强大的工厂,是所有bean的管理器: 而spring context是上下文运行环境,基于spring core之上的一个架构, 它之上 ...

  4. 多个IoC容器适配器设计及性能测试(Castle.Windsor Autofac Spring.Core)

    [转]多个IoC容器适配器设计及性能测试和容器选择 1. 采用的IoC容器和版本 Autofac.2.6.3.862 Castle.Windsor.3.1.0 Spring.Core.2.0.0 2. ...

  5. Spring core resourc层结构体系及JDK与Spring对classpath中资源的获取方式及结果对比

    1. Spring core resourc层结构体系 1.1. Resource相关结构体系 1.2. ResourceLoader相关体系 2. JDK与Spring对classpath中资源的获 ...

  6. Spring Core Programming(Spring核心编程) - AOP Concepts(AOP基本概念)

    1. What is aspect-oriented programming?(什么是面向切面编程?) Aspects help to modularize cross-cutting concern ...

  7. spring core

    https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#beans

  8. 关于如何使用Spring里@AliasFor注解进行注解的封装

    不知道大家每次使用Spring boot的时候有没有看过它启动类里 @SpringBootApplication这个注解呢?众所周知,这个注解是一个复合注解,但是注解是不能继承元注解的属性的,也就是说 ...

  9. 尚学堂Spring视频教程(三):Spring Core中的其他特性

    集合装配   如果bean中有一些集合属性,配置文件的配置如下 package com.bjsxt.dao.impl; import java.util.List; import java.util. ...

随机推荐

  1. selenium 参数设置-window.navigator.webdriver

    selenium 参数设置 selenium启动chrome基本上与真实环境类似,但有一些变量还是不一样,需要注意. 有些网站通过这些参数识别爬虫. window.navigator.webdrive ...

  2. TensorFlow基础三(Scope)

    用到变量名了,就涉及到了名字域的概念.通过不同的域来区别变量名,毕竟给所有变量都直接取不同名字还是有点辛苦的. 主要是name_scope和variable_scope,name_scope 作用于操 ...

  3. java问题 2019

    一.Java基础和高级 1.String类为什么是final的. 2.HashMap的源码,实现原理,底层结构. 3.反射中,Class.forName和classloader的区别 4.sessio ...

  4. uniGUI之学习方法(18)

    官方例子D:\Program Files\FMSoft\Framework\uniGUI\Demos\Desktop 在Design里Main上右键,View as Form看到变化的属性. 看出变化 ...

  5. 2019上海爱奇艺大数据Java实习生-面试记录

    目录 一轮 电话面试 二轮 代码笔试 三轮 技术面试 总结 附:电话面试问题点解惑 补充:面试未通过 一轮 电话面试 2019.04.28 16:21 [w]:面试官,[m]:我,下面的内容来自电话录 ...

  6. iOS性能优化-内存优化

    https://blog.csdn.net/a184251289/article/details/82589128 2018年09月10日 14:25:31 xingshao1990 阅读数:328 ...

  7. Java中进行Md5加密

    java文件 https://pan.baidu.com/s/1kXcif35  密码:3cjd 代码案例: package cn.itcast.estore.utils; import java.m ...

  8. Mini_Linux需要搭的环境

    1.bash:ifconfig:command not found sudo yum install -y net-tools 2.如果Linux系统是通过复制得到  需要更改hostname vi ...

  9. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 辅助类:清除浮动

    <!DOCTYPE html> <html> <head> <title>Bootstrap .clearfix 实例</title> &l ...

  10. 【剑指Offer面试编程题】题目1519:合并两个排序的链表--九度OJ

    题目描述: 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. (hint: 请务必使用链表.) 输入: 输入可能包含多个测试样例,输入以EOF结束. 对于每 ...