理解Java注解类型

一. 理解 Java 注解
注解本质是一个继承了 Annotation 的特殊接口,其具体实现类是 Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是 Java 运行时生成的动态代理对象 $Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用 AnnotationInvocationHandler 的 invoke 方法。该方法会从 memberValues 这个 Map 中索引出对应的值。而 memberValues 的来源是 Java 常量池。
实际上 Java 注解与普通修饰符 (public、static、void 等) 的使用方式并没有多大区别,下面的例子是常见的注解

1
2
3
4
5
6
7
8
9
10
11
12
public class AnnotationDemo {
    
   @Test
   public static void A(){
       System.out.println("Test.....");
   }
   @Deprecated
   @SuppressWarnings("uncheck")
   public static void B(){
  
   }
}

 

通过在方法上使用 @Test 注解后,在运行该方法时,测试框架会自动识别该方法并单独调用,@Test 实际上是一种标记注解,起标记作用,运行时告诉测试框架该方法为测试方法。而对于 @Deprecated 和 @SuppressWarnings(“uncheck”),则是 Java 本身内置的注解,在代码中,可以经常看见它们,但这并不是一件好事,毕竟当方法或是类上面有 @Deprecated 注解时,说明该方法或是类都已经过期不建议再用,@SuppressWarnings 则表示忽略指定警告,比如 @SuppressWarnings(“uncheck”),这就是注解的最简单的使用方式,那么下面我们就来看看注解定义的基本语法


二. 基本语法
声明注解与元注解
我们先来看看前面的 Test 注解是如何声明的:

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
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface OpenAPIMeta {
    /**
     * 字符参数长度(仅需要对字符串类型进行设置)。
     */
    String limit();
 
    /**
     * 参数示例值(很重要不要随意赋值,用于生成示例json)。
     */
    String demo();
 
    /**
     * 参数说明。
     */
    String remark();
 
    /**
     * 参数是否必填项(0为非必填 ;1为必填 )
     */
    int isRequired() default 0;
 
    /**
     * 是否有扩展参数说明
     */
    boolean hasExtend() default false;
 
    /**
     * 枚举对象完整类型限定名
     */
    String enumType() default "";
}

 

三. 注解支持的数据类型
所有基本类型(int,float,boolean,byte,double,char,long,short)
String
Class (如:Class<?> 或 Class<T>)
enum
Annotation
上述类型的数组

四. 获取类级注解

1
2
3
4
5
6
7
DomainEventHandlerMessageQueue dehmqAnnotation = null;
Annotation[] annotations = obj.getClass().getAnnotations();
for (Annotation x : annotations) {
if (x.annotationType() == DomainEventHandlerMessageQueue.class) {
    dehmqAnnotation = x;
    break;
}

 

五. 获取方法注解

1
2
3
4
5
6
7
8
9
10
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
    OpenAPIMeta apiAnnotation = null;
    for (Annotation x : field.getDeclaredAnnotations()) {
        if (x.annotationType() == OpenAPIMeta.class) {
            apiAnnotation = (OpenAPIMeta) x;
            break;
        }
    }
}