Java 注解
基本注解
- 内置标准注解
 
1 2 3 4 5
   | @Override        @Deprecated     @SuppressWarnings  @SafeVarargs    @FunctionalInterface 
   | 
 
- 元注解(用于注解其他注解)
 
1 2 3 4 5
   | @Target         @Retention      @Documented     @Inherited      @Repeatable    
   | 
 
注解分类
- 按保留策略(即声明注解的生命周期,@Retention)
 
- SOURCE:仅保留在源码中,编译时丢弃
 
- CLASS:保留到 class 文件,但 JVM 不加载(默认)
 
- RUNTIME:保留到运行时,可通过反射读取
 
- 按作用目标(即声明可以注解在哪些元素之上,@Target)
 
| 元素 | 
说明 | 
| ElementType.TYPE | 
注解在类、接口、枚举上 | 
| ElementType.FIELD | 
注解在类中的字段上 | 
| ElementType.METHOD | 
注解在类中的方法上 | 
| ElementType.PARAMETER | 
注解在方法的参数前 | 
| ElementType.CONSTRUCTOR | 
注解在类中构造方法上 | 
| ElementType.LOCAL_VARIABLE | 
注解在局部变量前 | 
| ElementType.ANNOTATION_TYPE | 
注解在注解上 | 
| ElementType.PACKAGE | 
注解在包名前 | 
组合注解
@Controller 注解用来配置访问路径等,@ResponseBody 注解用来表明不做视图渲染,直接展示方法的运行结果(一般是转成 json 返回),而@RestController 组合了两者的功能,可以配置访问路径,同时也可以直接展示方法的运行结果
1 2 3 4 5 6 7 8 9 10
   | @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Controller   @ResponseBody   public @interface RestController {       @AliasFor(annotation = Controller.class)     String value() default ""; }
   | 
 
使用案例
简化 Web 层配置,需求:统一 Controller 层的公共配置(如日志、权限校验)。
1 2 3 4 5 6
   | @RestController @RequestMapping("/api/v1") @CrossOrigin @Tag(name = "API接口")  public @interface RestApiController { }
   | 
 
1 2 3 4 5 6 7 8
   | @RestApiController public class UserController {          @GetMapping("/users")     public List<User> getUsers() {               } }
   | 
 
@AliasFor
显式别名
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping public @interface RequestMapping {       @AliasFor("path")     String[] value() default {};       @AliasFor("value")     String[] path() default {};        }
  | 
 
value 和 path 互为别名,互为别名的限制条件如下:
- 互为别名的属性其属性值类型、默认值,都是相同的。
 
- 互为别名的属性必须定义默认值。
 
- 互为别名的注解必须成对出现。
 
隐式别名
1 2 3 4 5 6 7 8 9 10 11 12
   | @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 {}; }
   | 
 
因为 value、groovyScripts、xmlFiles 都定义了别名@AliasFor(annotation = ContextConfiguration.class, attribute = “locations”),所以 value、groovyScripts 和 xmlFiles 也互为别名。
传递式隐式别名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | @MyTestConfig public @interface GroovyOrXmlTestConfig {
     @AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts")    String[] groovy() default {};
     @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")    String[] xml() default {}; }
  @ContextConfiguration public @interface MyTestConfig {
     @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")    String[] groovyScripts() default {}; }
   | 
 
@AliasFor 注解是允许别名之间的传递的,简单理解,如果 A 是 B 的别名,并且 B 是 C 的别名,那么 A 是 C 的别名
因为 MyTestConfig 中的 groovyScripts 属性是 ContextConfiguration 中的 locations 属性的别名;所以 xml 属性和 groovy 属性也互为别名
自定义注解
继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
   | public class SynthesizedAnnotationTest {       @Target({ ANNOTATION_TYPE, FIELD, TYPE })     @Retention(RUNTIME)     @interface Test1 {         String test1() default "test1";     }       @Target({ ANNOTATION_TYPE, FIELD, TYPE })     @Retention(RUNTIME)     @interface Test2 {         String test2() default "test2";     }       @Target({ ANNOTATION_TYPE, FIELD, TYPE })     @Retention(RUNTIME)     @Test2     @interface Test3 {         String test3() default "test3";     }       
 
 
      @Test3     static class Element {}         public static void main(String[] args) {         Test2 test2 = AnnotatedElementUtils.getMergedAnnotation(Element.class, Test2.class);         System.out.println(test2);              } }
  | 
 
覆盖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
   | public class SynthesizedAnnotationTest {       @Target({ ANNOTATION_TYPE, FIELD, TYPE })     @Retention(RUNTIME)     @interface Test1 {         String test1() default "test1";     }       @Target({ ANNOTATION_TYPE, FIELD, TYPE })     @Retention(RUNTIME)     @interface Test2 {         String test2() default "test2";     }       @Target({ ANNOTATION_TYPE, FIELD, TYPE })     @Retention(RUNTIME)     @Test2     @interface Test3 {         
 
 
 
          @AliasFor(annotation = Test2.class, attribute = "test2")         String test3() default "test3";     }       
 
 
 
      @Test3(test3 = "覆盖Test2属性中的test2方法")     static class Element {}
      public static void main(String[] args) {         Test2 test2 = AnnotatedElementUtils.getMergedAnnotation(Element.class, Test2.class);                           System.out.println(test2.test2());     } }
  | 
 
合并
1 2 3 4 5 6 7 8 9 10 11 12
   | @Documented @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @A @B public @Interface C{        @AliasFor(annotation = A.class, attribute = "value")     String aValue();          @AliasFor(annotation = B.class, attribute = "value")     String bValue(); }
   |