无论是在JDK还是框架中,注解都是很重要的一部分,我们使用过很多注解,但是你有真正去了解过他的实现原理么?你有去自己写过注解么?
一、相关
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
在JDK中定义了许多注解,其作用大致可以分为以下几类:
- 编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
- 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
- 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
二、注解功能的实现
我们以spring中比较常见的Autowired来举例分析
1.创建注解
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
注解的创建看起来很像接口,需要用@interface来修饰,然后我们看到在Autowired注释之上还有三个注释来进行修饰。
他们三个都叫做“元注释”,Jdk5所定义的源注释还有@Retention、@Documented、@Inherited,这些类型和它们所支持的类在java.lang.annotation包中可以找到。
@Target
用于描述注解的使用范围,也就是在什么时候生效,一般情况下,我们的注释可能在packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)等任何一个地方生效。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
注:比较有意思的是,@Target也被自己修饰,这可能有更深层的原理,在此不再深入
通过源码我们看出@Target下有一个类型为ElementType[] 的值value(),进入ElementType[],这是一个枚举类型,他提供了我们对于这个值的选项,可供选择的值有:
public enum ElementType {
/** 描述类、接口(包括注解类型) 或enum声明 */
TYPE,
/** 描述域 */
FIELD,
/** 描述方法 */
METHOD,
/** 描述参数 */
PARAMETER,
/** 描述构造器*/
CONSTRUCTOR,
/** 描述本地值 */
LOCAL_VARIABLE,
/** 描述注解类型 */
ANNOTATION_TYPE,
/** 描述包 */
PACKAGE,
/**
* 描述类型参数
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* 一个类型的用户
*
* @since 1.8
*/
TYPE_USE
}
在Autowired中我们给值是{ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE},也就是说,我们的这个注解可以用于构造函数、方法、参数、域,注解等等。