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. ...
随机推荐
- 【快学SpringBoot】SpringBoot+Docker构建、运行、部署应用
前言 Docker技术发展为当前流行的微服务提供了更加便利的环境,使用SpringBoot+Docker部署和发布应用,其实也是一件比较简单的事情.当前,前提是得有Docker的基础. 源码在文末 文 ...
- Struts2.0笔记二
Mvc与servlet 1.1 Servlet的优点 1. 是mvc的基础,其他的框架比如struts1,struts2,webwork都是从servlet基础上发展过来的.所以掌握servle ...
- 六 Struts2访问Servlet的API方式一:完全解耦合的方式
注意: 完全解耦合的方式,这种方式只能获得代表request.session.application的数据的Map集合. 不能操作这些对象的本身的方法. 1 jsp: <%@ page lang ...
- SpringBoot + redis + @Cacheable注解实现缓存清除缓存
一.Application启动类添加注解 @EnableCaching 二.注入配置 @Bean public CacheManager cacheManager(RedisTemplate redi ...
- Nodejs回调加超时限制两种实现方法
odejs回调加超时限制两种实现方法 Nodejs下的IO操作都是异步的,有时候异步请求返回太慢,不想无限等待回调怎么办呢?我们可以给回调函数加一个超时限制,到一定时间还没有回调就表示失败,继续后面的 ...
- 访问docker desktop创建的Hyper-v虚拟机DockerDesktopVM
平常我们部署kubernetes ,一般都是先安装个linux操作系统,不管是centos或者ubuntu或者其他,都是我们手工操作的.安装好的这个操作系统都开启了SSH,能够远程登录访问. 但是do ...
- 「HNOI2010」弹飞绵羊
「HNOI2010」弹飞绵羊 传送门 考虑分块. 每一个位置 \(i\) ,记 \(to[i]\) 表示从这个位置一直往右跳回落在哪个位置. 然后修改的时候直接暴改,查询也是暴跳,复杂度 \(O(n ...
- 「JSOI2010」满汉全席
前言 由于蒟蒻才刚开始学 \(\text{2-SAT}\),所以题解中有的地方可能不够精炼,望多包涵! 题目描述 题目意思很简单,标准的\(\text{2-SAT}\)问题模型.那么我们就先来介绍一下 ...
- 如何查看python的notebook文件.ipynb
文章中的ipython notebook和jupyter notebook基本可以互换,不过使用ipython notebook会警告您要使用jupyter notebook.其他没有区别. ---- ...
- MYSQL--“Row size too large (> 8126)”
将表的引擎改为MyISAM就可以,如下图. 因为新数据库mysql默认的引擎是InnoDB