自定义注解
这是一篇前导文,为后面打算写的 Spring Boot 读取不到启动类中的自定义注解做铺垫。
你既然都看到这篇文章了,想必比我都了解什么是注解、注解能用来干嘛。之前都对注解怀着“敬畏”的心态,觉得能自定义注解的人一定很厉害,确实的确如此,我见到过的那些人确实都非常厉害。不过话说回来了,注解也不是什么牛鬼蛇神,**它就是一个标签,只不过是这个标签保存在源代码中,并且能被 annotation API 工具(我把它当做注解解析器)操作。**如果只是定义一个注解,而不去写它的解析器,那的确没什么卵用……
语法和规范
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Test {
int value() ;
int key() default 1;
}
上面就是最常见的注解的定义语法了,它用 @interface 关键字定义,注解中的属性定义不太一样,它用类似方法的形式,这些属性要么有默认值,要么在使用注解时提供这些值,注解处理器其实就是利用反射来取到注解的属性,然后再根据属性值来具体做出相应处理。没什么,不要给自己设限。注解也会被编译成 .class 文件
如果一个注解中没有任何属性,就被称作标记注解(mark annotation)。
根据 Java Language Specification(JLS 9.6),注解的名字不能和类名或者接口名相同,原话如下:
It is a compile-time error if an annotation type has the same simple name as any of its enclosing classes or interfaces. 其实这也可以理解,毕竟都是以 .java 结尾嘛
所有的注解都直接继承自 java.lang.annotation.Annotation(注意这货是个接口),这也不难理解,Class 类中的 getAnnotations() 方法返回的都是 Annotation[] 类型的数组。
元注解
并不想去接受这些概念性质的东西,元注解是一种特殊的注解,它被设计用来解释其他注解何时、何处起作用。说白了就是元注解专门负责新注解的创建,如上述你看到的 @Test 注解一样。
Java 提供了四种元注解:
名称 | 参数 |
---|---|
@Target | ElementType 类型的数组,指明注解能应用在何处,凡是你能想到的地方(类、方法声明、参数、包甚至是局部变量)都能使用注解,具体在 ElementType 枚举类中有定义 |
@Retention | 指明注解在什么级别保存该注解,参数为 RetentionPolicy 枚举类,可选值有 SOURCE(被编译器丢弃)、CLASS(在 class 文件中可用,会被 JVM 丢弃)、RUNTIME(JVM 运行时也保留该注解,可通过反射的方式读取该注解的信息),一般情况下我们都是选择 RUNTIMR,你可以留心一下 Lombok 大多是在 SOURCE 级别 |
@Documented | 此注解包含在 Javadoc 中 |
@Inheried | 允许子类继承父类中的注解 |
我们定义自己的注解的时候,需要用这些元注解来指明这个注解可以被用到哪里、在哪个级别起作用。
注解中若定义了名为 value 的元素,并且在应用该注解的时候,此元素是唯一一个需要被赋值的元素,那么此时无需使用 “名-值” 对的这种语法,只需在括号中给出 value 元素所需的值即可。——《Java 编程思想》
注解处理器
上面也说了,光有注解没卵用,注解处理器才会让注解发挥出作用。
未完待续!
参考文章:
[1.] Java注解(三) 自定义注解与提取注解
[2.] 自定义Java注解处理器