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. MSSQL2005数据库快照(SNAPSHOT)初探

    定义:数据库快照是数据库(称为“源数据库”)的只读静态视图.在创建时,每个数据库快照在事务上都与源数据库一致.多个快照可以位于一个源数据库中,并且可以作为数据库始终驻留在同一服务器实例上.在创建数据库 ...

  2. Linux 允许root用户远程登陆

    首先确保ssh服务已经安装: ps -e | grep ssh or service ssh start 如果没有安装则: apt-get install ssh 安装完之后 查看 /etc/ssh/ ...

  3. matlab练习程序(龙格库塔法)

    非刚性常微分方程的数值解法通常会用四阶龙格库塔算法,其matlab函数对应ode45. 对于dy/dx = f(x,y),y(0)=y0. 其四阶龙格库塔公式如下: 对于通常计算,四阶已经够用,四阶以 ...

  4. git安装以及gitlib配置

    安装Git:详见http://www.cnblogs.com/xiuxingzhe/p/9300905.html 开通gitlab(开通需要咨询所在公司的gitlab管理员)账号后,本地Git仓库和g ...

  5. 修改iso ghost xp镜像 ie主页

    使用ghost explorer把镜像中在"Documents and SettingsAdministrator"里的文件"NTUSER.DAT",提取出来, ...

  6. 「HNOI2003」消防局的设立

    题目 [内存限制:$256 MiB$][时间限制:$1000 ms$] [标准输入输出][题目类型:传统][评测方式:文本比较] 题目描述 2020 年,人类在火星上建立了一个庞大的基地群,总共有 $ ...

  7. C. Maximum Median 二分

    C. Maximum Median 题意: 给定一个数组,可每次可以选择一个数加1,共执行k次,问执行k次操作之后这个数组的中位数最大是多少? 题解:首先对n个数进行排序,我们只对大于中位数a[n/2 ...

  8. SqlSession为什么可以提交事务

    本应在开始读MyBatis源码时首先应该了解下MyBatis的SqlSession的四大对象:Executor.StatemenHandler.ParameterHandler.ResultHandl ...

  9. C#中as用法---转载

    转载 jiang13824690 发布于2018-07-24 11:19:00 阅读数 3302 收藏 展开 在程序中,进行类型转换时常见的事,C#支持基本的强制类型转换方法,例如  Object o ...

  10. 三、js提交请求加载启动动画、请求完成成功回调、注销加载动画

    1.通过Query  post方式进行异步请求方法 jQuery.post(url, [data], [callback], [type]) 参数说明: url:发送请求地址 data:待发送 Key ...