Java注解原理学习

77 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情

Java注解原理学习

相信对于注解的使用已经很熟练啦,自从JDK5引入Annotation后,在很多框架中都有使用到注解,为我们的开发带来了很多遍历。

其实注解就本身而言并不会影响代码的运行,在某种程度上它就是一种特殊的注释,如果没有解析它的注解处理器,那么它就没有啥作用了。

注解处理器可以分为编译时期注解处理器和运行时期注解处理器其中

基于编译时期注解处理器实现的框架有MapStruct、Lombok等,而运行时期注解处理器就是我们平常所使用的,例如Spring框架中扫描Bean对象、AOP切面等。

那么注解的原理是什么呢?@interface是一个什么东西呢?注解是类还是接口呢?

下面就来学习一下~

简单定义一个注解SimpleAnnotation

public @interface SimpleAnnotation {
​
    String value() default "just annotation";
}
​

随后使用javap命令查看对应的字节码,可以看到SimpleAnnotation是一个继承java.lang.annotation.Annotation的一个接口,同时Value也是一个抽象方法。

// javap -c SimpleAnnotation
Compiled from "SimpleAnnotation.java"
public interface pers.czj.annotation.SimpleAnnotation extends java.lang.annotation.Annotation {
  public abstract java.lang.String value();
}

可以看到官方介绍Annotation接口是所有注解的一个通用父接口

image.png

那么注解在Java中本质上是一个接口,那么我们是如何调用它的相关方法来获得值得呢?例如下面的例子:

@SimpleAnnotation
public class TestAnnotation {
​
    public static void main(String[] args) {
        SimpleAnnotation simpleAnnotation = TestAnnotation.class.getAnnotation( SimpleAnnotation.class );
        simpleAnnotation.value();
    }
}

simpleAnnotation.value()在字节码中是调用INVOKEINTERFACE指令来实现的

INVOKEINTERFACE用以调用接口方法,在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用。(Invoke interface method)

所以我们通过getAnnotation方法获得的注解是一个代理对象,核心是通过AnnotationInvocationHandler类来生成注解的动态代理对象。

image.png 总结:Java注解是一个继承了java.lang.annotation.Annotation的接口,使用时返回一个基于JDK动态代理生成的对象