@AliasFor注解的使用注意事项详解 ╰+哭是因爲堅強的太久メ 2024-03-25 16:48 20阅读 0赞 #### 文章目录 #### * 一、@AliasFor注解简介 * 二、使用场景 * 三、 注意事项(重点关注) * 四、使用步骤 * * 1.指定别名,属性互换 * * 1.1自定义注解 * 1.2使用 * 1.3注意事项 * 1.4 Spring中的@RequestMapping注解 * 2.将一个注解上的属性值传递给另一个注解对另一个注解的属性进行别名覆盖 * * 2.1举例说明 * 2.2注意事项 * 3.组合多个注解,通过一个注解达到使用多个注解的效果 * * 3.1 这是3个注解 * 3.2合并注解 * 3.3使用 * 五、总结 ## 一、@AliasFor注解简介 ## @AliasFor注解是在spring源码当中提供的,见名知义,他是为了别名而自定义的注解! 但这并不是java原生支持的,需要通过Spring中提供的工具类org.springframework.core.annotation.`AnnotationUtils`或者org.springframework.core.annotation.`AnnotatedElementUtils`来解析。AnnotatedElementUtils内部还是调用的AnnotationUtils ## 二、使用场景 ## * 在注解中一对属性上通过声明@AliasFor,进行属性互换。 * 在注解上声明了另一个注解,对另一个注解的属性进行别名覆盖(也可以理解为将一个注解上的属性值传递给另一个注解 ## 三、 注意事项(重点关注) ## `指定别名,属性互换的情况下,通过AnnotationUtils仍然可以获取到值,而通过java原生的方式则无法获取`。 是因为Spring其实是自己实现了jdk动态的拦截器来实现别名功能. 但是: 如果同时设置,并且互为别名的两个属性值不一样就会报错,抛出如下异常: 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自定义注解 #### @Target({ ElementType.TYPE, ElementType.METHOD}) @Documented @Retention(RetentionPolicy.RUNTIME) public @interface MenuAuthCheck { @AliasFor("value") String permission() default ""; @AliasFor("permission") String value() default ""; } #### 1.2使用 #### @MenuAuthCheck("test_admin") #### 1.3注意事项 #### 1. 构成别名对的每个属性都必须用@AliasFor注释,并且属性或值必须引用别名对中的另一个属性。 2. 这两个属性的必须拥有相同的返回值类型。 3. 别名属性必须声明默认值。 4. 这两个属性必须拥有相同的默认值。 #### 1.4 Spring中的@RequestMapping注解 #### 我们通常直接使用 @RequestMapping("/web"") value注解注释也表明 这是 path的别名 @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举例说明 #### @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface TestAnnotation { @AliasFor("name") String value() default ""; @AliasFor("value") String name() default ""; } @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个注解 #### @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合并注解 #### /* * 合并注解 */ @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使用 #### @MyCombinedAnnotation(value = "perfect", name = "who", desc = "this is a merge annotation") 等价于三个注解同时使用 @TestAnnotation1 ("hello") @TestAnnotation2 (name = "world") @TestAnnotation3 (desc = "this is a merge annotation") public class TestClass { } ## 五、总结 ## 1. 我们在使用时这个注解时,可以直接填写内容,而不用主动指定"name"和"value"属性,从而达到了隐示表明属性别名的效果。 2. `指定别名,属性互换的情况下,通过AnnotationUtils仍然可以获取到值,而通过java原生的方式则无法获取`。 是因为Spring其实是自己实现了jdk动态的拦截器来实现别名功能. 但是: 如果同时设置,并且互为别名的两个属性值不一样就会报错 `所以互为别名,指定一个即可,两个都会有相同的值` **作用** * 指定别名,属性互换 * 将一个注解上的属性值传递给另一个注解对另一个注解的属性进行别名覆盖 * 组合多个注解,通过一个注解达到使用多个注解的效果
还没有评论,来说两句吧...