Spring中的@AliasFor标签的用途

《SpringBoot系列八》:Spring注解别名@AliasFor和覆盖(含原理) Spring注解别名@AliasFor和覆盖(含原理) 阅读详情

在Spring的众多注解中,经常会发现很多注解的不同属性起着相同的作用,比如@RequestMapping的value属性和path属性,这就需要做一些基本的限制,比如value和path的值不能冲突,比如任意设置value或者设置path属性的值,都能够通过另一个属性来获取值等等。为了统一处理这些情况,Spring创建了@AliasFor标签。

使用
@AliasFor标签有几种使用方式。

1,在同一个注解内显示使用;比如在@RequestMapping中的使用示例:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
 
    @AliasFor("path")
    String[] value() default {};
 
    @AliasFor("value")
    String[] path() default {};
 
    //...
}

又比如@ContextConfiguration注解中的value和locations属性:

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ContextConfiguration {
    @AliasFor("locations")
    String[] value() default {};
 
    @AliasFor("value")
    String[] locations() default {};
    //...
}

在同一个注解中成对使用即可,比如示例代码中,value和path就是互为别名。但是要注意一点,@AliasFor标签有一些使用限制,但是这应该能想到的,比如要求互为别名的属性属性值类型,默认值,都是相同的,互为别名的注解必须成对出现,比如value属性添加了@AliasFor(“path”),那么path属性就必须添加@AliasFor(“value”),另外还有一点,互为别名的属性必须定义默认值。

那么如果违反了别名的定义,在使用过程中就会报错,我们来做个简单测试:

@ContextConfiguration(value = "aa.xml", locations = "bb.xml")
public class AnnotationUtilsTest {
    @Test
    public void testAliasfor() {
        ContextConfiguration cc = AnnotationUtils.findAnnotation(getClass(),
                ContextConfiguration.class);
        System.out.println(
                StringUtils.arrayToCommaDelimitedString(cc.locations()));
        System.out.println(StringUtils.arrayToCommaDelimitedString(cc.value()));
    }
}

执行测试,报错;value和locations互为别名,不能同时设置;

稍微调整一下代码:

@MyAnnotation
@ContextConfiguration(value = "aa.xml", locations = "aa.xml")
public class AnnotationUtilsTest {

或者

@MyAnnotation
@ContextConfiguration(value = "aa.xml")
public class AnnotationUtilsTest {

运行测试,均打印出:

aa.xml
aa.xml
2,显示的覆盖元注解中的属性;
先来看一段代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AopConfig.class)
public class AopUtilsTest {

这段代码是一个非常熟悉的基于JavaConfig的Spring测试代码;假如现在我有个癖好,我觉得每次写@ContextConfiguration(classes = AopConfig.class)太麻烦了,我想写得简单一点,我就可以定义一个这样的标签:

@Retention(RetentionPolicy.RUNTIME)
@ContextConfiguration
public @interface STC {
 
    @AliasFor(value = "classes", annotation = ContextConfiguration.class)
    Class<?>[] cs() default {};
 
}

1,因为@ContextConfiguration注解本身被定义为@Inherited的,所以我们的STC注解即可理解为继承了@ContextConfiguration注解;
2,我觉得classes属性太长了,所以我创建了一个cs属性,为了让这个属性等同于@ContextConfiguration属性中的classes属性,我使用了@AliasFor标签,分别设置了value(即作为哪个属性的别名)和annotation(即作为哪个注解);

使用我们的STC:

@RunWith(SpringJUnit4ClassRunner.class)
@STC(cs = AopConfig.class)
public class AopUtilsTest {
 
    @Autowired
    private IEmployeeService service;

正常运行;
这就是@AliasFor标签的第二种用法,显示的为元注解中的属性起别名;这时候也有一些限制,比如属性类型,属性默认值必须相同;当然,在这种使用情况下,@AliasFor只能为作为当前注解的元注解起别名;

3,在一个注解中隐式声明别名;
这种使用方式和第二种使用方式比较相似,我们直接使用Spring官方文档的例子:

 @ContextConfiguration
 public @interface MyTestConfig {
 
    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] value() default {};
 
    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] groovyScripts() default {};
 
    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] xmlFiles() default {};
 }

可以看到,在MyTestConfig注解中,为value,groovyScripts,xmlFiles都定义了别名@AliasFor(annotation = ContextConfiguration.class, attribute = “locations”),所以,其实在这个注解中,value、groovyScripts和xmlFiles也互为别名,这个就是所谓的在统一注解中的隐式别名方式;

4,别名的传递;
@AliasFor注解是允许别名之间的传递的,简单理解,如果A是B的别名,并且B是C的别名,那么A是C的别名;
我们看一个例子:

@MyTestConfig
 public @interface GroovyOrXmlTestConfig {
 
    @AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts")
    String[] groovy() default {};
 
    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] xml() default {};
 }

1,GroovyOrXmlTestConfig把 @MyTestConfig(参考上一个案例)作为元注解;
2,定义了groovy属性,并作为MyTestConfig中的groovyScripts属性的别名;
3,定义了xml属性,并作为ContextConfiguration中的locations属性的别名;
4,因为MyTestConfig中的groovyScripts属性本身就是ContextConfiguration中的locations属性的别名;所以xml属性和groovy属性也互为别名;
这个就是别名的传递性;

原理
明白@AliasFor标签的使用方式,我们简单来看看**@AliasFor标签的使用原理**;
首先来看看该标签的定义:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AliasFor {
 
    @AliasFor("attribute")
    String value() default "";
 
    @AliasFor("value")
    String attribute() default "";
 
    Class<? extends Annotation> annotation() default Annotation.class;
 
}

可以看到,@AliasFor标签自己就使用了自己,为value属性添加了attribute属性作为别名;

那么就把这个注解放在我们需要的地方就可以了么?真就这么简单么?我们来做一个例子:
1,创建一个注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
 
    @AliasFor("alias")
    String value() default "";
 
    @AliasFor("value")
    String alias() default "";
 
}

在该注解中,我们让alias和value属性互为别名;
2,完成测试类:

@MyAnnotation(value = "aa", alias = "bb")
public class AnnotationUtilsTest {
 
    @Test
    public void testAliasfor2() {
        MyAnnotation ann = getClass().getAnnotation(MyAnnotation.class);
        System.out.println(ann.value());
        System.out.println(ann.alias());
    }
}

我们将MyAnnotation放在AnnotationUtilsTest上,可以看到,我们故意将value和alias值设置为不一样的,然后在测试代码中分别获取value()和alias()的值,结果打印:
aa
bb

WTF?和预期的不一样?原因很简单,AliasFor是Spring定义的标签,要使用他,只能让Spring来处理,修改测试代码:

@MyAnnotation(value = "aa", alias = "bb")
public class AnnotationUtilsTest {
 
    @Test
    public void testAliasfor3() {
        MyAnnotation ann = AnnotationUtils.findAnnotation(getClass(),
                MyAnnotation.class);
        System.out.println(ann.value());
        System.out.println(ann.alias());
    }
}

这次我们使用Spring的AnnotationUtils工具类的findAnnotation方法来获取标签,然后再次打印value()和alias()值:

如愿报错;所以,使用@AliasFor最需要注意一点的,就是只能使用Spring的AnnotationUtils工具类来获取;

而真正在起作用的,是AnnotationUtils工具类中的 A synthesizeAnnotation(A annotation, AnnotatedElement annotatedElement)方法;
这个方法传入注解对象,和这个注解对象所在的类型,返回一个经过处理(这个处理就主要是用于处理@AliasFor标签)之后的注解对象,简单说,这个方法就是把A注解对象—-(经过处理)——>支持AliasFor的A注解对象,我们来看看其中的关键代码:

DefaultAnnotationAttributeExtractor attributeExtractor =
    new DefaultAnnotationAttributeExtractor(annotation, annotatedElement);
InvocationHandler handler = 
    new SynthesizedAnnotationInvocationHandler(attributeExtractor);
return (A) Proxy.newProxyInstance(annotation.getClass().getClassLoader(),
    new Class<?>[] {(Class<A>) annotationType, SynthesizedAnnotation.class}, handler);

可以看到,本质原理就是使用了AOP来对A注解对象做了一次动态代理,而用于处理代理的对象为SynthesizedAnnotationInvocationHandler;我们来看看SynthesizedAnnotationInvocationHandler中的重要处理代码:

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (isEqualsMethod(method)) {
        return annotationEquals(args[0]);
    }
    if (isHashCodeMethod(method)) {
        return annotationHashCode();
    }
    if (isToStringMethod(method)) {
        return annotationToString();
    }
    if (isAnnotationTypeMethod(method)) {
        return annotationType();
    }
    if (!isAttributeMethod(method)) {
        String msg = String.format("Method [%s] is unsupported for synthesized annotation type [%s]", method,
            annotationType());
        throw new AnnotationConfigurationException(msg);
    }
    return getAttributeValue(method);
}

在invoke(即拦截方法中,这个拦截方法就是在注解中获取属性值的方法,不要忘了,注解的属性实际上定义为接口的方法),其次判断,如果当前执行的方法不是equals、hashCode、toString、或者属性是另外的注解,或者不是属性方法,之外的方法(这些方法就是要处理的目标属性),都调用了getAttributeValue方法,所以我们又跟踪到getAttributeValue方法的重要代码:

String attributeName = attributeMethod.getName();
        Object value = this.valueCache.get(attributeName);
        if (value == null) {
            value = this.attributeExtractor.getAttributeValue(attributeMethod);

这里我们重点关注的是如果没有缓存到值(这个先不用管),直接调用attributeExtractor.getAttributeValue方法获取属性值,那么,很容易猜到,如果属性有@AliasFor注解,就应该是这个方法在处理;那我们来看看这个方法又在做什么事情:

attributeExtractor是一个AnnotationAttributeExtractor类型,这个对象是在构造SynthesizedAnnotationInvocationHandler时传入的,默认是一个DefaultAnnotationAttributeExtractor对象;而DefaultAnnotationAttributeExtractor是继承AbstractAliasAwareAnnotationAttributeExtractor,看名字,真正的处理AliasFor标签的动作,应该就在这里面,于是继续看代码:

public final Object getAttributeValue(Method attributeMethod) {
        String attributeName = attributeMethod.getName();
        Object attributeValue = getRawAttributeValue(attributeMethod);
 
        List<String> aliasNames = this.attributeAliasMap.get(attributeName);
        if (aliasNames != null) {
            Object defaultValue = AnnotationUtils.getDefaultValue(getAnnotationType(), attributeName);
            for (String aliasName : aliasNames) {
                Object aliasValue = getRawAttributeValue(aliasName);
 
                if (!ObjectUtils.nullSafeEquals(attributeValue, aliasValue) &&
                        !ObjectUtils.nullSafeEquals(attributeValue, defaultValue) &&
                        !ObjectUtils.nullSafeEquals(aliasValue, defaultValue)) {
                    throw new AnnotationConfigurationException(...)
                }
                if (ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) {
                    attributeValue = aliasValue;
                }
            }
        }
 
        return attributeValue;
    }

对原代码做了些改造,但是我们能清晰的看到重点:
1,首先正常获取当前属性的值;
2,List aliasNames = this.attributeAliasMap.get(attributeName);得到所有的标记为别名的属性名称;
3,Object aliasValue = getRawAttributeValue(aliasName);遍历获取所有别名属性的值;
4,三个重要判断,attributeValue、aliasValue、defaultValue相同,我们前面介绍的@AliasFor标签的传递性也是在这里体现;如果不相同,直接抛出异常;否则正常返回属性值;

至此,AliasFor的执行过程分析完毕;

营销反作弊之 异常行为分析模型(一),附带python代码 通过对用户行为进行深入的分析,识别出与常规模式不符的异常行为,可以有效检测并阻止虚假广告点击、刷单、点击欺诈等欺诈行为。本文将详细探讨营销反欺诈中异常行为分析的方法,介绍如何通过数据采集、清洗、行为建模与异常检测,准确识别潜在的欺诈行为,并提供 Python 实现代码示例。**监督学习 (Supervised Learning):**在标注数据的帮助下,训练机器学习模型使其能预测未知数据的结果。营销反欺诈异常行为分析的整体流程涉及多个环节,确保通过对用户行为的深入分析,及时识别潜在的欺诈行为。 阅读详情

相关推荐

Arduino——GY39大气压、温湿度、光照模块

前几天买东西的时候买了一个GY39,这个模块集成了温湿度,大气压,海拔,光照一体,使用起来很方面。它有两种工作模式使用串口模式时需要搭配转接板,我选择了IIC模式,看一下通信协议吧,就是关于高八位和低八位的数据。看一下接线。

戚晨夕的博客 2605

Spring中@AliasFor注解的作用及原理

Spring中@AliasFor注解的作用及实心原理

Brucelwl的博客 4512

AI训练加速30%!用numactl玩转多显卡绑核的隐藏技巧

本文深入探讨了如何利用Linux系统的numactl工具,通过精确的NUMA绑核策略优化多GPU AI训练性能。文章详细解析了NUMA架构对性能的影响,提供了从拓扑探查、命令实战到多卡脚本化部署的完整指南,并分享了性能验证与常见陷阱,帮助开发者实现高达30%的训练加速。

web99的专栏 448

Spring——@AliasFor注解

文章目录@AliasFor @AliasFor

zl13101758272的博客 1131

VBA中如何使用Edge内核Browser?

在微软宣布停止对IE的支持后,许多使用VBA中Web Browser的用户遇到了困境,因为Web Browser使用的IE内核。然而微软并没有给出支持Edge的新版Web Browser,网上许多第三方的库也不够完善。经过调研,libEdge可以较好的和VBA集成,实现在Excel中打开Browser,甚至能够通过执行js代码,获取web页面的信息。项目需要WebView2Loader.dll和LibEdge.dll两个库,区分x86和x64版本。

金木AI 2398

FFmpeg实战:5分钟搞定m3u8视频下载与ts文件合并(附完整命令)

本文详细介绍了如何使用FFmpeg快速下载m3u8视频并合并ts文件为mp4格式。通过简洁的命令行操作,读者可以轻松完成视频处理任务,包括环境准备、链接获取、下载合并及性能优化等实用技巧,特别适合需要高效处理流媒体内容的用户。

weixin_30836759的博客 221

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

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

10km的专栏 813

个人顶级AI助手OpenClaw(Clawdbot) - 新手快速入门指南

本文详细介绍了个人顶级AI助手OpenClaw(Clawdbot) 的快速入门指南,包括安装部署和使用配置及注意事项

program哲学 5305

Java 注解篇:@AliasFor

在 Spring 框架中,注解的使用非常广泛。为了增强注解的灵活性和可组合性,Spring 引入了一个非常有用的元注解 —— @AliasFor。它主要用于为注解属性之间建立别名关系,使得在使用注解时可以更自由地配置参数,同时也为注解组合与继承提供了强大支持。

x² 2315

你知道几种数字地与模拟地连接方式及优缺点?

频率选择性:磁珠的阻抗特性随频率变化,只对某个频点的噪声有显著抑制作用,对于频率不确定或无法预知的情况,可能不是最佳选择。在实际应用中,选择合适的连接方式需要根据具体的电路频率、信号类型、设计要求等因素综合考虑,以达到最佳的电磁兼容效果.高频信号干扰:在高频电路中,单点接地可能导致信号回流路径过长,增加地线电感,从而引入高频噪声。限制噪声电流:0欧姆电阻相当于一个非常窄的电流通路,能够有效地限制环路电流,使噪声得到抑制。抑制高频信号:电感对高频信号有较大的阻碍作用,可以有效抑制高频噪声。

linkking27的博客 801

【K210+STM32项目】基于K210与STM32协同工作的智能垃圾分类系统设计与实现(更新3.0版本)(完整工程资料源码)

STM32F407STM32F407_2(含有app功能)

嵌入式技术开发 2492

@AliasFor的使用方法

注意,我们需要在MyCombinedAnnotation中加上@MyAnnotation1、@MyAnnotation2、@MyAnnotation3三个注解,表示这个新注解中包含了这三个注解的所有属性,可以通过@MyCombinedAnnotation来代替这三个注解的使用。当然,你也可以理解为将一个注解上的属性值传递给另一个注解,我个人更习惯采用这种理解,因为后续可以通过一个注解组合多个注解进行使用,通过一个注解将值传递给多个注解,而这与java的继承的概念并不相同。

Evan's Blog ٩(๑❛ᴗ❛๑)۶ 3650

【教程4>第6章>第15节】 基于I+jQ复数信号的LS信道估计和均衡实现1——matlab仿真分析,QPSK为例

在基于QPSK调制的通信系统中,LS信道估计和均衡是用于补偿信道失真、提高信号传输质量的重要技术。以下将详细介绍基于I+jQ复数信号的 LS 信道估计和均衡的实现原理与过程。可以看到,通过线性插值之后,QPSK信号的星座图可以模糊的看到四个星座点(图2),通过非线性插值之后,可以清晰的看到QPSK的四个星座点(图3)。可以看到,信道均衡显著提高了通信系统的可靠性和有效性。

FPGA/MATLAB学习教程/源码/项目合作开发 657

Spring中的@AliasFor标签

原创文章,转载请注明出处在Spring的众多注解中,经常会发现很多注解的不同属性起着相同的作用,比如@RequestMapping的value属性和path属性,这就需要做一些基本的限制,比如value和path的值不能冲突,比如任意设置value或者设置path属性的值,都能够通过另一个属性来获取值等等。为了统一处理这些情况,Spring创建了@AliasFor标签。使用@AliasFor标签有...

wolfcode_cn的博客 7万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Spring @AliasFor使用

同一注解类中的@AliasFor 这种场景比较简单,首先定义注解 package com.uu.annotation; import org.springframework.core.annotation.AliasFor; import java.lang.annotation.*; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @in

万物皆字节 714

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Spring源码深度解析(郝佳)-学习-源码解析-@AliasFor标签

在研究Spring源码关于注解解析时,发现有源码中有很大的篇幅在处理关于AliasFor标签。我在网上找了一下,发现Spring中的@AliasFor标签 这篇博客对@AliasFor的使用己经介绍得很详细了,只是对源码的具体处理方面,我觉得,如果不是研究过源码的同学,可能还是觉得镜花水月,因此,今天,对其中的一个具体的示例做一下分析,希望对大家有用,先上示例吧 AliasFor.java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.MET

黄裳博客 659

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

@AliasFor 注解

Spring 框架提供了很丰富的注解可以让我们很方便的进行 Spring 配置,今天要讲的注解——@AliasFor之前你可能并没有关注过,因为平时开发时我们的确不太会用到。我关注到这个注解是因为我经常翻看 Spring 的源代码,在 Spring 提供的注解中大量的用到了这个注解,对这个注解不熟悉的话会影响你对代码的判断,而且有些代码看的总是似懂非懂的,很难受(强迫症,哈哈),比如说下面这段代码。 上面的代码大致能“猜测”出 @AliasFor 是为了属性起别名,但是 @AliasFor 的使用场景,使用

L__ear的博客 466

Spring @AliasFor

原文地址:https://blog.youkuaiyun.com/wolfcode_cn/article/details/80654730   在Spring的众多注解中,经常会发现很多注解的不同属性起着相同的作用,比如@RequestMapping的value属性和path属性,这就需要做一些基本的限制,比如value和path的值不能冲突,比如任意设置value或者设置path属性的值,都能够通过另...

ken-jl 的专栏 611
上一篇: Please umount the filesystem and rectify the problem(s)
下一篇: windows快速安装 Rabbit MQ
Small_StarOne
博客等级 码龄8年 11粉丝 34原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值