@AliasFor注解的使用注意事项详解

🍓 简介:java系列技术分享(👉持续更新中...🔥)

🍓 初衷:一起学习、一起进步、坚持不懈

🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏

🍓 希望这篇文章对你有所帮助,欢迎点赞 👍 收藏 ⭐留言 📝

一、@AliasFor注解简介

@AliasFor注解是在spring源码当中提供的,见名知义,他是为了别名而自定义的注解!

但这并不是java原生支持的,需要通过Spring中提供的工具类org.springframework.core.annotation.AnnotationUtils或者org.springframework.core.annotation.AnnotatedElementUtils来解析。AnnotatedElementUtils内部还是调用的AnnotationUtils

二、使用场景

  • 在注解中一对属性上通过声明@AliasFor,进行属性互换。
  • 在注解上声明了另一个注解,对另一个注解的属性进行别名覆盖(也可以理解为将一个注解上的属性值传递给另一个注解

三、 注意事项(重点关注)

指定别名,属性互换的情况下,通过AnnotationUtils仍然可以获取到值,而通过java原生的方式则无法获取。 是因为Spring其实是自己实现了jdk动态的拦截器来实现别名功能. 但是: 如果同时设置,并且互为别名的两个属性值不一样就会报错,抛出如下异常:

java 复制代码
Caused by: org.springframework.core.annotation.AnnotationConfigurationException: Different @AliasFor mirror values for annotation [com.sysmenu.annotion.MenuAuthCheck] declared on com.controller.ZnjProjectNoticeController.publishNoticeAnnouncement(com.dto.ZnjProjectNoticeAnnouncementInsertDTO); attribute 'permission' and its alias 'value' are declared with values of [lecture] and [lecture_report].
	at org.springframework.core.annotation.AnnotationTypeMapping$MirrorSets$MirrorSet.resolve(AnnotationTypeMapping.java:711)
	at org.springframework.core.annotation.AnnotationTypeMapping$MirrorSets.resolve(AnnotationTypeMapping.java:666)
	at org.springframework.core.annotation.TypeMappedAnnotation.<init>(TypeMappedAnnotation.java:134)
	at org.springframework.core.annotation.TypeMappedAnnotation.<init>(TypeMappedAnnotation.java:118)
	at org.springframework.core.annotation.TypeMappedAnnotation.of(TypeMappedAnnotation.java:599)
	at org.springframework.core.annotation.MergedAnnotation.of(MergedAnnotation.java:610)
	at org.springframework.core.type.classreading.MergedAnnotationReadingVisitor.visitEnd(MergedAnnotationReadingVisitor.java:96)

所以互为别名,指定一个即可,两个都会有相同的值

四、使用步骤

1.指定别名,属性互换

1.1自定义注解

java 复制代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface MenuAuthCheck {
    @AliasFor("value")
    String permission() default "";

    @AliasFor("permission")
    String value() default "";
}

1.2使用

java 复制代码
@MenuAuthCheck("test_admin")

1.3注意事项

  1. 构成别名对的每个属性都必须用@AliasFor注释,并且属性或值必须引用别名对中的另一个属性。
  2. 这两个属性的必须拥有相同的返回值类型。
  3. 别名属性必须声明默认值。
  4. 这两个属性必须拥有相同的默认值。

1.4 Spring中的@RequestMapping注解

我们通常直接使用

java 复制代码
@RequestMapping("/web"")

value注解注释也表明 这是 path的别名

java 复制代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";
 
 		/**
	 * The primary mapping expressed by this annotation.
	 * <p>This is an alias for {@link #path}. For example,
	 * {@code @RequestMapping("/foo")} is equivalent to
	 * {@code @RequestMapping(path="/foo")}.
	 * <p><b>Supported at the type level as well as at the method level!</b>
	 * When used at the type level, all method-level mappings inherit
	 * this primary mapping, narrowing it for a specific handler method.
	 * <p><strong>NOTE</strong>: A handler method that is not mapped to any path
	 * explicitly is effectively mapped to an empty path.
	 */
    @AliasFor("path")
    String[] value() default {};
 
    @AliasFor("value")
    String[] path() default {};
 
    RequestMethod[] method() default {};
 
    String[] params() default {};
 
    String[] headers() default {};
 
    String[] consumes() default {};
 
    String[] produces() default {};
}

2.将一个注解上的属性值传递给另一个注解对另一个注解的属性进行别名覆盖

2.1举例说明

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestAnnotation {
 
    @AliasFor("name")
    String value() default "";
 
    @AliasFor("value")
    String name() default "";
 
}
java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@MyAnnotation
public @interface TestAliasAnnotation {
 
    @AliasFor(annotation = TestAnnotation .class, attribute = "value")
    String name() default "";
}

将TestAliasAnnotation 注解中的name属性传递给TestAnnotation 注解的value属性,进行覆盖

2.2注意事项

  • 被标记@AliasFor的属性和atttibute所指向的元注解属性必须有相同的返回值类型。

3.组合多个注解,通过一个注解达到使用多个注解的效果

3.1 这是3个注解

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation1 {
    String value();
}
 
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation2 {
    String name();
}
 
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation3 {
    String desc();
}

使用@AliasFor注解来定义一个新注解,将这三个注解组合起来如下:

3.2合并注解

java 复制代码
/*
* 合并注解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@TestAnnotation1 
@TestAnnotation2 
@TestAnnotation3 
public @interface TestMergeAnnotation {
    @AliasFor(annotation = TestAnnotation1 .class, attribute = "value")
    String value() default "";
 
    @AliasFor(annotation = TestAnnotation2 .class, attribute = "name")
    String name() default "";
 
    @AliasFor(annotation = TestAnnotation3 .class, attribute = "desc")
    String desc() default "";
}

在这个新注解中使用了@AliasFor注解,使一个注解达到同时使用3个注解的效果

3.3使用

java 复制代码
@MyCombinedAnnotation(value = "perfect", name = "who", desc = "this is a merge annotation")

等价于三个注解同时使用

java 复制代码
@TestAnnotation1 ("hello")
@TestAnnotation2 (name = "world")
@TestAnnotation3 (desc = "this is a merge annotation")
public class TestClass {
}

五、总结

  1. 我们在使用时这个注解时,可以直接填写内容,而不用主动指定"name"和"value"属性,从而达到了隐示表明属性别名的效果。
  2. 指定别名,属性互换的情况下,通过AnnotationUtils仍然可以获取到值,而通过java原生的方式则无法获取。 是因为Spring其实是自己实现了jdk动态的拦截器来实现别名功能. 但是: 如果同时设置,并且互为别名的两个属性值不一样就会报错 所以互为别名,指定一个即可,两个都会有相同的值

作用

  • 指定别名,属性互换
  • 将一个注解上的属性值传递给另一个注解对另一个注解的属性进行别名覆盖
  • 组合多个注解,通过一个注解达到使用多个注解的效果
相关推荐
喵爸的小作坊1 分钟前
StreamPanel:一个让 SSE 调试不再痛苦的 Chrome 插件
前端·后端·http
神奇小汤圆2 分钟前
字符串匹配算法
后端
无限大68 分钟前
为什么网站需要"域名"?——从 IP 地址到网址的演进
后端
树獭叔叔14 分钟前
LangGraph Memory 机制
后端·langchain·aigc
BullSmall14 分钟前
Tomcat11证书配置全指南
java·运维·tomcat
永不停歇的蜗牛16 分钟前
K8S之创建cm指令create和 apply的区别
java·容器·kubernetes
Java编程爱好者17 分钟前
OpenCVSharp:了解几种特征检测
后端
爱学习的小可爱卢21 分钟前
JavaEE进阶——SpringBoot统一功能处理全解析
java·spring boot·后端·java-ee
汤姆yu24 分钟前
基于springboot的二手物品交易系统的设计与实现
java·spring boot·后端
Java水解25 分钟前
基于Rust实现爬取 GitHub Trending 热门仓库
数据结构·后端