Java注解的基本原理

  简介:注解的本质就是一个继承了Annotation接口的接口,一个注解准确意义上来说,只不过是一种特殊注释而已,如果没有解析他的代码,他可能连注释都不如。
 解析一个类或者方法的注解往往有两种形式,一种是编译期直接的扫描,一种是运行期反射。

  基础:Java中有以下几个元注解

    @Target: 注解的作用目标
    @Retention: 注解的生命周期
    @Documented: 注解是否应当被包含在javaDoc文档中
    @Inherited: 是否允许子类继承该注解

  1、@Target中作用范围对应的枚举值:

    ElementType.TYPE:允许被修饰的注解作用在类、接口和枚举上
    ElementType.FIELD:允许作用在属性字段上
    ElementType.METHOD:允许作用在方法上
    ElementType.PARAMETER:允许作用在方法参数上
    ElementType.CONSTRUCTOR:允许作用在构造器上
    ElementType.LOCAL_VARIABLE:允许作用在本地局部变量上
    ElementType.ANNOTATION_TYPE:允许作用在注解上
    ElementType.PACKAGE:允许作用在包上

  2、@RetentionPolicyd取值对应枚举:
    RetentionPolicy.SOURCE:当前注解编译期可见,不会写入 class 文件    
    RetentionPolicy.CLASS:类加载阶段丢弃,会写入 class 文件
    RetentionPolicy.RUNTIME:永久保存,可以反射获取
  3、@Inherited 注解修饰的注解是具有可继承性的,也就说我们的注解修饰了一个类,而该类的子类将自动继承父类的该注解
    注解和反射
    虚拟机规范定义了一系列和注解相关的属性表,也就是说,无论是字段、方法或者是类本身,如果被注解修饰了,就可以被写进字节码文件,属性表有以下几种:
      RuntimeVisibleAnnotations:运行时可见的注解
      RuntimeInVisibleAnnotations:运行时不可见的注解
      RuntimeVisibleParameterAnnotations:运行时可见的方法参数注解
      RuntimeInVisibleParameterAnnotations:运行时不可见的方法参数注解
      AnnotationDefault:注解类元素的默认值
      所以,对于一个类或者接口来说,Class类中提供以下一些方法用于反射注解
        getAnnotation:返回指定的注解
        isAnnotationPresent:判定当前元素是否被指定注解修饰
        getAnnotations:返回所有的注解
        getDeclaredAnnotation:返回本元素的指定注解
        getDeclaredAnnotations:返回本元素的所有注解,不包含父类继承而来的

  总结:
    首先,我们通过键值对的形式可以为注解属性赋值。
    接着,你用注解修饰某个元素,编译器将在编译期扫描每个类或者方法上的注解,会做一个基本的检查,你的这个注解是否允许作用在当前位置,最后会将注解信息写入元素的属性表。
    然后,当你进行反射的时候,虚拟机将所有生命周期在 RUNTIME 的注解取出来放到一个 map 中,并创建一个 AnnotationInvocationHandler 实例,把这个 map 传递给它。
    最后,虚拟机将采用 JDK 动态代理机制生成一个目标注解的代理类,并初始化好处理器。
    那么这样,一个注解的实例就创建出来了,它本质上就是一个代理类,你应当去理解好 AnnotationInvocationHandler 中 invoke 方法的实现逻辑,这是核心。
一句话概括就是,通过方法名返回注解属性值

posted @ 2018-12-29 16:23  金仙儿追鹿仙  阅读(693)  评论(0编辑  收藏  举报