深入理解Java注解

一、注解知其然

注解的定义

  1. Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate.(翻译:注解是元数据的一种形式,它提供有关程序的数据,该数据不属于程序本身。注释对其注释的代码的操作没有直接影响)——Lesson: Annotations
  2. 注解是放在Java源码的类、方法、字段、参数前的一种特殊“注释”。 —— 使用注解
  3. Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。——Java 注解
  4. 注解是那些插入到源码中,使用其他工具可以对其进行处理的标签。 —— 《Java核心技术 卷二 高级特性 原书第10版》
  5. 注解是 Java 5 引入的,用来为类、方法、字段、参数等Java结构提供额外信息的机制。——《深入拆解Java虚拟机》
  6. 注解是一种元数据。可以用来标注Java类、方法、参数、类属性、包等,使用注解处理器、AOP等可以获取注解信息对程序做相应的修改。——我的总结

JDK常见注解

  • @Override
    用来注解覆盖超类方法的子类方法。如果方法带有 @Override 标记,要么覆盖了 Object 类中的方法,要么覆盖超类(类、抽象类、接口)中的方法,否则编译器生成错误消息。

  • @Deprecated: 修饰未来将被抛弃的类/方法/属性等等;
    用来注解不建议使用的类/方法/属性,为了兼容或者给出时间让使用者修改成其他使用方式,例如:调用了加 @Deprecated 的方法,则编译器会告警信息。

  • @SuppressWarnings
    若使用了带有 @Deprecated 注解的方法,想关闭告警,则加入 @SuppressWarnings 注解可以关闭编译器警告信息。

JDK不常见注解

  • @FunctionalInterface
    Java 8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。

    顺便提下啥是函数式接口:所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法,比如下图所示。

Java元注解

作用在其他注解的注解。

  • @Target 指明定义的注解的作用域,其值包括:
    * ElementType.CONSTRUCTOR: 构造方法声明
    * ElementType.FIELD: 属性/字段声明;
    * ElementType.LOCAL_VARIABLE: 局部变量声明;
    * ElementType.METHOD: 方法声明;
    * ElementType.PACKAGE: 包声明;
    * ElementType.PARAMETER: 参数声明;
    * ElementType.TYPE: 类接口声明;
    * ElementType.ANNOTATION_TYPE: 注解类型声明;
    * ElementType.TYPE_PARAMETER: 类型参数声明(@since 1.8);
    * ElementType.TYPE_USE: 类型使用(@since 1.8)

  • @Retention 自定义注解的生命周期,其值包括:
    * RetentionPolicy.SOURCE: 只在源码显示,编译时丢弃;
    * RetentionPolicy.CLASS: 编译时记录到.class中,运行时忽略;
    * RetentionPolicy.RUNTIME: 运行时存在,可通过反射来读取。

  • @Inherited 被标注的注解是被继承的
    * 类继承关系中@Inherited的作用:类继承关系中,子类会继承父类使用的注解中被@Inherited修饰的注解
    * 接口继承关系中@Inherited的作用:接口继承关系中,子接口不会继承父接口中的任何注解,不管父接口中使用的注解有没有被@Inherited修饰
    * 类实现接口关系中@Inherited的作用:类实现接口时不会继承任何接口中定义的注解

  • @Documented
    @Documented 注解表明这个注解应该被 javadoc 工具记录. 默认情况下,javadoc 是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中,是一个标记注解,没有成员。

Spring中常见注解及作用

  • @Autowired 是我们使用得最多的注解,其实就是 autowire=byType 就是根据类型的自动注入依赖(基于注解的依赖注入),可以被使用再属性域,方法,构造函数上。
  • @Qualifier 就是 autowire=byName, @Autowired注解判断多个bean类型相同时,就需要使用 @Qualifier("xxBean") 来指定依赖的bean的id:
  • @Resource 属于JSR250标准,用于属性域和方法上。是 byName 类型的依赖注入。使用方式:@Resource(name="xxBean"). 不带参数的 @Resource 默认值类名首字母小写。
  • JSR-330标准javax.inject.*中的注解(@Inject, @Named, @Qualifier, @Provider, @Scope, @Singleton)。@Inject就相当于@Autowired, @Named 就相当于 @Qualifier, 另外 @Named 用在类上还有 @Component的功能。
  • @Component, @Controller, @Service, @Repository, 这几个注解不同于上面的注解,上面的注解都是将被依赖的bean注入进入,而这几个注解的作用都是生产bean, 这些注解都是注解在类上,将类注解成spring的bean工厂中一个一个的bean。@Controller, @Service, @Repository基本就是语义更加细化的@Component。
  • @PostConstruct 和 @PreDestroy 不是用于依赖注入,而是bean 的生命周期。类似于 init-method(InitializeingBean) destory-method(DisposableBean)

二、注解知其所以然

注解处理器

注解处理器,也称插件化注解处理(Pluggable Annotation Processing)APIJSR 269提供一套标准API来处理AnnotationsJSR 175,实际上JSR 269不仅仅用来处理Annotation,我觉得更强大的功能是它建立了Java 语言本身的一个模型,它把method、package、constructor、type、variable、enum、annotation等Java语言元素映射为Types和Elements,从而将Java语言的语义映射成为对象,我们可以在javax.lang.model包下面可以看到这些类。所以我们可以利用JSR 269提供的API来构建一个功能丰富的元编程(metaprogramming)环境。JSR 269用Annotation Processor在编译期间而不是运行期间处理Annotation, Annotation Processor相当于编译器的一个插件,所以称为插入式注解处理.如果Annotation Processor处理Annotation时(执行process方法)产生了新的Java代码,编译器会再调用一次Annotation Processor,如果第二次处理还有新代码产生,就会接着调用Annotation Processor,直到没有新代码产生为止。每执行一次process()方法被称为一个"round",这样整个Annotation processing过程可以看作是一个round的序列。JSR 269主要被设计成为针对Tools或者容器的API。这个特性虽然在JavaSE 6已经存在,但是很少人知道它的存在。下一篇介绍的Java奇技淫巧-lombok就是使用这个特性实现编译期的代码插入的。另外,如果没有猜错,像IDEA在编写代码时候的标记语法错误的红色下划线也是通过这个特性实现的。KAPT(Annotation Processing for Kotlin),也就是Kotlin的编译也是通过此特性的。
Pluggable Annotation Processing API的核心是Annotation Processor即注解处理器,一般需要继承抽象类javax.annotation.processing.AbstractProcessor。注意,与运行时注解RetentionPolicy.RUNTIME不同,注解处理器只会处理编译期注解,也就是RetentionPolicy.SOURCE的注解类型,处理的阶段位于Java代码编译期间。

字节码操作注解

可以在Java代码从编译,加载,链接过程对字节码修改或操作进而操作注解。

Spring注解实现原理

Spring 中注解的处理基本都是通过实现接口 BeanPostProcessor 后置处理器来进行的,处理注解的实现主要有:AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor 等

posted @ 2020-08-05 16:53  行云(xingyun)  阅读(193)  评论(0编辑  收藏  举报