spring core:@AliasFor的派生性
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的派生性的更多相关文章
- 【Spring开发】—— Spring Core
原文:[Spring开发]-- Spring Core 前言 最近由于一些工作的需要,还有自己知识的匮乏再次翻开spring.正好整理了一下相关的知识,弥补了之前对spring的一些错误认知.这一次学 ...
- vs2012+Spring.Core.dll
Ⅰ.Spring的点点滴滴--序章 spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架 .net篇(环境为vs2012+Spring.Core.dll) 新建一个控制台 u ...
- spring core 与 context理解
Spring core是核心层,拥有这BeanFactory这个强大的工厂,是所有bean的管理器: 而spring context是上下文运行环境,基于spring core之上的一个架构, 它之上 ...
- 多个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. ...
- Spring core resourc层结构体系及JDK与Spring对classpath中资源的获取方式及结果对比
1. Spring core resourc层结构体系 1.1. Resource相关结构体系 1.2. ResourceLoader相关体系 2. JDK与Spring对classpath中资源的获 ...
- Spring Core Programming(Spring核心编程) - AOP Concepts(AOP基本概念)
1. What is aspect-oriented programming?(什么是面向切面编程?) Aspects help to modularize cross-cutting concern ...
- spring core
https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#beans
- 关于如何使用Spring里@AliasFor注解进行注解的封装
不知道大家每次使用Spring boot的时候有没有看过它启动类里 @SpringBootApplication这个注解呢?众所周知,这个注解是一个复合注解,但是注解是不能继承元注解的属性的,也就是说 ...
- 尚学堂Spring视频教程(三):Spring Core中的其他特性
集合装配 如果bean中有一些集合属性,配置文件的配置如下 package com.bjsxt.dao.impl; import java.util.List; import java.util. ...
随机推荐
- crm系统和e_store商场的比较总结
e_store用了:Java.Servlet.JSP.Oracle.JQuery.Mybatis,tomcat技术 crm用了 :Java.JSP.Oracle.JQuery,Mybatis,spri ...
- 最大流dinic板子
题目: https://www.luogu.com.cn/problem/P3376 #include <bits/stdc++.h> using namespace std; ; con ...
- spring boot中不能识别RestController
参考:https://blog.csdn.net/qq_16739693/article/details/80271987
- RIFF
RIFF全称为资源互换文件格式(Resources Interchange File Format),是Windows下大部分多媒体文件遵循的一种文件结构. RIFF文件所包含的数据类型由该文件的扩展 ...
- webpack中devtool的配置方案[开发模式]---[线上模式]
// 开发模式下 module.exports = { mode: 'development', devtool: 'cheap-module-eval-source-map' } // 线上模式下 ...
- Day11 - J - Brave Game HDU - 1846
十年前读大学的时候,中国每年都要从国外引进一些电影大片,其中有一部电影就叫<勇敢者的游戏>(英文名称:Zathura),一直到现在,我依然对于电影中的部分电脑特技印象深刻.今天,大家选择上 ...
- isEqual判断相等性
1.isEqual方法用来判断两个比较者的内存地址是否一样.为了细分,有isEqualToString.isEqualToNumber.isEuqalToValue等,使用时一定要精确使用,比如虽然N ...
- SVM数学原理推导
//2019.08.17 #支撑向量机SVM(Support Vector Machine)1.支撑向量机SVM是一种非常重要和广泛的机器学习算法,它的算法出发点是尽可能找到最优的决策边界,使得模型的 ...
- 为何以及如何学Linux系统?
在当今的社会中,linux用处实在是太过广泛了.现在用在服务器和嵌入式上的Linux发行版本数不胜数,桌面上linux只占1%的比例,但这不代表linux比windows和mac 做得差,实际上桌面系 ...
- 华为轮值CEO,富士康却坚持独裁,二者究竟有什么不一样?
谈到深圳龙华的大企业,人们会很自然地想到华为和富士康,两家公司毗邻,有两个门仅仅隔着一条马路,都是世界500强,对国家,对社区的经济发展有着重要贡献,员工压力最大的时候,也都出现过自杀的情况,一个讲究 ...