spring-core:理解@AliasFor注解的作用

@AliasFor是spring注解体系中一个非常重要且基础的注解。顾名思义,它的基本作用就是为注解字段定义一个别名。

基本作用:字段别名

	@Testpublic void test3AliasFor() {try {{CasbanScan casbanScan = AnnotationUtils.findAnnotation(UserSummy.class, CasbanScan.class);System.out.println(casbanScan);}} catch (Throwable e) {e.printStackTrace();fail();}}@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface CasbanScan {@AliasFor("basePackages")String[] value() default {};@AliasFor("value")String[] basePackages() default {};}@CasbanScan("hello")public static class UserSummy{}public static class VipSummy extends UserSummy{}

输出

@CasbanScan(basePackages=[hello], value=[hello])

上面的输出可以看到虽然UserSummy类上的@CasbanScan注解只定义了value字段但通过AnnotationUtils.findAnnotation方法获取到的CasbanScan实例basePackages字段也是有与value字段相同的值,这就是@AliasFor注解的基本作用。

更多:注解继承

除了为注解字段定义别名之外,@AliasFor注解更重要的作用是为注解增加了类似Java普通类的继承功能,如下是@AliasFor的定义源码:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AliasFor {/*** Alias for {@link #attribute}.* <p>Intended to be used instead of {@link #attribute} when {@link #annotation}* is not declared &mdash; for example: {@code @AliasFor("value")} instead of* {@code @AliasFor(attribute = "value")}.*/@AliasFor("attribute")String value() default "";/*** The name of the attribute that <em>this</em> attribute is an alias for.* @see #value*/@AliasFor("value")String attribute() default "";/*** The type of annotation in which the aliased {@link #attribute} is declared.* <p>Defaults to {@link Annotation}, implying that the aliased attribute is* declared in the same annotation as <em>this</em> attribute.*/Class<? extends Annotation> annotation() default Annotation.class;}

上面源码可以看到@AliasFor不仅有value字段还有annotation字段,这个字段的字面作用是声明别名属性的所属的注解类型。
怎么理解呢?
我们知道注解(Annotation)类虽然也是一个接口(@interface),但它与Java的标准接口(interface)是不太一样的,它没有继承能力,
如下普通的Java interface类可以从另一个接口类继承(extends),但@interface不行

public interface Request{}
public interface WebRequest extends Request{}

这在一定程序上限制了注解的应用场景。

spring-core的注解体系通过@AliasFor注解为注解设计提供了继承能力。这个继承能力就体现在了@AliasForannotation字段。

如果不定义annotation字段
@AliasForvalueattribute字段用于指定@AliasFor所在字段为同当前注解类内的字段别名。如下例子:value上定义的@AliasFor("basePackages")即指定valuebasePackages字段的别名,反之亦然。

	public @interface CasbanScan {@AliasFor("basePackages")String[] value() default {};@AliasFor("value")String[] basePackages() default {};}

如果定义了annotation字段
annotation字段可以理解为指定当前字段为定义在当前注解上的注解类指定字段的别名。

如下示例:
@RequestComponent注解上定义了@ScanConfig注解,@RequestComponent注解的subClassFirstly字段上定义了@AliasFor(annotation = ScanConfig.class,attribute="subClassFirstly")
即定义该字段为@ScanConfigsubClassFirstly的别名

@Retention(RetentionPolicy.RUNTIME)
public @interface ScanConfig {String subClassFirstly() default "";
}@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.ANNOTATION_TYPE})
@ScanConfig
public @interface RequestComponent {@AliasFor("associated")String value() default "";@AliasFor("value")String associated() default "";@AliasFor(annotation = ScanConfig.class,attribute="subClassFirstly")String subClassFirstly() default "";
}

我们可以再定义一个注解@WebComponent也使定义一个firstly字段使用同样的@AliasFor注解,注意这个字段firstly字段与@RequestComponentsubClassFirstly并不同名

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@ScanConfig
public @interface WebComponent {String value() default "";@AliasFor(annotation = ScanConfig.class,attribute="subClassFirstly")String firstly() default "";
}

展现继承能力

如下示例,调用AnnotatedElementUtils.findMergedAnnotation方法获取类上定义的@ScanConfig

	@Testpublic void test4AliasFor() {try {{ScanConfig scanConfig= AnnotatedElementUtils.findMergedAnnotation(UseRequestComponent.class, ScanConfig.class);System.out.printf("ScanConfig:%s in %s\n",UseRequestComponent.class.getSimpleName(), AnnotationUtils.getAnnotationAttributes(scanConfig));assertEquals("hello", scanConfig.subClassFirstly());}{ScanConfig scanConfig = AnnotatedElementUtils.findMergedAnnotation(UseWebComponent.class, ScanConfig.class);System.out.printf("ScanConfig:%s in %s\n",UseWebComponent.class.getSimpleName(), AnnotationUtils.getAnnotationAttributes(scanConfig));assertEquals("world", scanConfig.subClassFirstly());}} catch (Throwable e) {e.printStackTrace();fail();}}@RequestComponent(subClassFirstly="hello")public static class UseRequestComponent{}@WebComponent(firstly = "world")public static class UseWebComponent{}

输出

ScanConfig:UseRequestComponent in {subClassFirstly=hello}
ScanConfig:UseWebComponent in {subClassFirstly=world}

如上示例,我们可以从定义了注解@RequestComponent(subClassFirstly="hello")UseRequestComponent类直接获取@ScanConfig注解值
也可以从定义了注解@WebComponent(firstly = "world")UseWebComponent类直接获取@ScanConfig注解值
虽然@RequestComponent@WebComponent是两个不同的注解类,但因为它们都有@ScanConfig注解。所以AnnotatedElementUtils.findMergedAnnotation方法可以从定义了这两个注解的类上读取它们共同定义的@ScanConfig注解,
从这点来看是不是可以视为@RequestComponent@WebComponent都继承了将@ScanConfig注解呢?

所以@AliasFor注解可以为不同的注解提供共同的字段,类似于父类字段。有了这个能力,基于spring-core注解框架设计自己的注解体系就提供了很大的灵活性和便利性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/2702.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis篇:缓存更新策略最佳实践

前景&#xff1a; 缓存更新是redis为了节约内存而设计出来的一个东西&#xff0c;主要是因为内存数据宝贵&#xff0c;当我们向redis插入太多数据&#xff0c;此时就可能会导致缓存中的数据过多&#xff0c;所以redis会对部分数据进行更新&#xff0c;或者把他叫为淘汰更合适&a…

代理池项目查询

github.com:jhao104/proxy_pool.git https://github.com/jhao104/proxy_pool/ 如果&#xff0c;可以用 GitHub: Let’s build from here GitHub代替 https://bgithub.xyz/ 仅限学习使用

libssh C++封装(二)

1 概述 libssh是一个在客户端和服务器端实现SSHv2协议的多平台C库。使用libssh,您可以远程执行程序、传输文件、使用安全透明的隧道、管理公钥等等。本文描述的对libssh客户端功能的C++封装。 libssh下载地址 3 实现 3.1 Session Session类型管理SSH连接会话 3.1.1 Sessio…

开放式耳机怎样选性价比高?五大性能出色爆款推荐!

在今年的耳机市场&#xff0c;开放式耳机如雨后春笋般涌现&#xff0c;为消费者提供了更多的选择。在这样一个产品繁多的市场中&#xff0c;如何挑选出一款音质上乘、性能卓越的开放式耳机&#xff0c;确实是一个值得探讨的问题。相较于长时间佩戴传统入耳式耳机可能带来的耳朵…

Jenkins 打包报错记录 error: index-pack died of signal 15

问题背景&#xff0c;打包每次到92%时就会报错&#xff0c;试了好几次都是同样的错误 14:56:53 fatal: index-pack failed 14:56:53 14:56:53 at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandIn(CliGitAPIImpl.java:2734) 14:56:53 at org.jenkinsci.plugi…

【UE 材质】水波纹效果

效果 模拟雨水打落在水面上的效果 步骤 1. 下载所需纹理和纹理 纹理2. 新建一个材质&#xff0c;这里命名为“M_WaterRipples” 打开“M_WaterRipples”&#xff0c;添加一个纹理采样节点&#xff0c;纹理使用第一步下载的纹理 将纹理采样节点的R通道连接到基础颜色&#x…

MySQL、Oracle查看最大连接数和当前连接数

文章目录 1. MySQL2. Oracle 1. MySQL -- 查看最大连接数 show variables like max_connections; select max_connections; -- select * from performance_schema.session_variables where VARIABLE_NAME in (max_connections); -- select * from performance_schema.global…

产品推荐 | 基于Intel (Altera) Cyclone IV 打造的水星Mercury CA1核心板

01 产品概述 水星Mercury CA1核心板结合了Intel Cyclone IV FPGA、通用接口如USB 2.0和Gigabit Ethernet&#xff0c;具备大量的LVDS I/O、大容量DDR2 SDRAM和大量硬件乘法器&#xff0c;这些使得水星CA1核心板非常适合数字信号处理、网络、高速I/O以及使用Intel NiosII软处理…

某酒业集团数字化转型规划(169页附下载)

某酒业集团数字化转型项目实施方案建议书(P169).rar是一个极具参考价值的资料&#xff0c;它详细地阐述了如何利用数字化技术来推动企业转型。这份建议书以IBM的先进技术和某酒业集团的实际应用需求为基础&#xff0c;提出了一套全面、系统的数字化转型解决方案。该方案首先对某…

禅道安装(非docker 版本)(一键部署版)

1.安装包下载地址 https://www.zentao.net/dl/zentao/18.5/ZenTaoPMS.18.5.zbox_64.tar.gzLinux一键安装包内置了Apache、PHP、MySQL和XXD 服务&#xff0c;不需要再单独安装。 2.上传到linux服务器 scp /Users/admin/Downloads/ZenTaoPMS.18.5.zbox_64.tar.gz root192.168.…

java体育馆使用预约平台的设计与实现(springboot+mysql源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的体育馆使用预约平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 体育馆使用预约平台的…

从浏览器内核到Web性能优化:揭秘底层原理与实战技巧

从浏览器内核到Web性能优化&#xff1a;揭秘底层原理与实战技巧 一、浏览器内核与渲染引擎 浏览器内核&#xff0c;也被称为渲染引擎&#xff0c;是浏览器的核心组件&#xff0c;负责解析HTML、CSS和JavaScript&#xff0c;并将这些源代码转换为用户在屏幕上看到的可交互网页…

Win10 打开有些软件主界面会白屏不显示,其他软件都正常

环境&#xff1a; Win10专业版 英伟达4070 显卡 问题描述&#xff1a; Win10 打开有些软件主界面会白屏不显示,打开远程协助软件AIRMdesk,白色&#xff0c;其他软件都正常 解决方案&#xff1a; 网上说电脑没有接显示器独立显卡的关系导致 我是只有一台主机&#xff0c;没…

【QT教程】QT6QFuture与并发

QT6QFuture与并发 使用AI技术辅助生成 QT界面美化视频课程 QT性能优化视频课程 QT原理与源码分析视频课程 QT QML C扩展开发视频课程 免费QT视频课程 您可以看免费1000个QT技术视频 免费QT视频课程 QT统计图和QT数据可视化视频免费看 免费QT视频课程 QT性能优化视频免费看 免…

Flask Web框架入门教程

一、Flask简介 Flask是一个轻量级的Web应用框架&#xff0c;使用Python编写。相比于Django等其他大型框架&#xff0c;Flask更加灵活和轻量&#xff0c;非常适合小型到中型的应用开发。它有一个强大的扩展库&#xff0c;可以方便地添加各种功能。 二、安装Flask 你可以使用p…

手撕netty源码(二)- 初始化ServerBootstrap

文章目录 前言一、ServerBootstrap 的创建和初始化1.1 创建1.2 初始化group1.3 初始化channel1.3 初始化option和attr1.4 初始化handler 和 childHandler 总结 前言 接上一篇&#xff1a;手撕netty源码&#xff08;一&#xff09;- NioEventLoopGroup 本篇讲解 ServerBootstra…

项目开发的详细步骤(精华版)

项目开发是指从项目启动到项目交付的全过程&#xff0c;涵盖了需求分析、设计、编码、测试、部署等多个环节。以下为项目开发的详细步骤&#xff1a; 1. 项目启动与规划 项目立项 商业论证&#xff1a;分析项目投资回报率、风险、市场前景等&#xff0c;确定项目价值和可行性…

Vue

文章目录 Vue1. 创建Vue实例2. 插值表达式3. 响应式特性4. 常用指令4.1 内容渲染指令4.2 条件渲染指令4.3 事件绑定指令4.4 单向属性绑定指令4.5 双向属性绑定指令4.6 列表渲染指令 5. 修饰符5.1 事件修饰符5.2 键盘事件修饰符5.3 修饰符串联5.4 v-model 修饰符 6. computed计算…

Android SDK Manager安装Google Play Intel x86 Atom_64 System Image依赖问题

Package Google Play Intel x86 Atom_64 System Image,Android API R, revision 2 depends on SDK Platform Android R Preview, revision 2 问题 一开始以为网络还有依赖包没有勾选&#xff0c;尝试了很多次&#xff0c;勾选这边报错对应的license即可。此时点击一下其他licen…

CountDownLatch使用错误+未最终断开连接导致线程池资源耗尽

错误描述&#xff1a; 我设置了CountDownLatch对线程的协作做出了一些限制&#xff0c;但是我发现运行一段时间以后便发现定时任务不运行了。 具体代码&#xff1a; public void sendToCertainWeb() throws IOException, InterruptedException {List<String> urlList …