冀教网 - 河北教师网站 - 专注于冀教版课本资源

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 58|回复: 0

标记接口,注解和注解处理器的前世今生

[复制链接]

4万

主题

4万

帖子

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
124999
发表于 2020-5-24 07:00 | 显示全部楼层 |阅读模式
目录

标记接口,注解和注解处理器的前世今生
简介

相信大部分的开发者都用过注解,尤其是对使用过Spring的开发者来说,注解是现代Spring中不可获取的一部分。Spring从最开始的xml配置到后面的注解配置,不论是从编程习惯还是项目的构建,都对我们程序员产生了非常重要的影响。
除了使用Spring自带的注解之外,我们还可以自定义注解。然后通过AOP来对注解进行拦截从而处理相应的业务逻辑。
除了Spring之外,其实JDK本身自带注解,本文将会深入探讨注解的起源和两种不同的使用方式。
更多精彩内容且看:
更多内容请访问www.flydean.com
注解的起源和marker interfaces

先看一个最简单的注解:
  1. @CustUserAnnotationpublic class CustUser {}
复制代码
上面我们将CustUser标记为一个自定义的注解@CustUserAnnotation。
注解其实是在JDK 5中引入的。那么在JDK 5之前,注解是用什么方式来表示的呢?答案就是marker interfaces。
marker interfaces中文翻译叫做标记接口,标记接口就是说这个接口使用来做标记用的,内部并没有提供任何方法或者字段。
在java中有很多标记接口,最常见的就是Cloneable,Serializable,还有java.util包中的EventListener和RandomAccess。
以Cloneable为例:
  1. /* * @since   1.0 */public interface Cloneable {}
复制代码
该接口从java1.0就开始有了。实现该接口的类才能够调用Object中的clone方法。
我们在代码中如何判断类是否实现了Cloneable接口呢?
  1. public Object clone() throws CloneNotSupportedException {        if (this instanceof Cloneable) {            return super.clone();        } else {            throw new CloneNotSupportedException();        }    }
复制代码
很简单,通过instanceof来判断是否是Cloneable即可。
marker interfaces好用是好用,但是有一些缺点,比如没有额外的元数据信息,功能太过单一,并且会和正常的interface混淆。实现起来也比一般的interface复杂。
正式由于这些原因,在JDK5中,引入了注解Annotation。
注解的定义

注解是由@interface来定义的。创建一个annotation需要指定其target和retention,并可以自定义参数。
我们举个例子:
  1. @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface CustUserAnnotation {    int value();    String name();    String[] addresses();}
复制代码
上面是我自定义的一个注解。
Retention

Retention表示注解将会在什么阶段可见。它有三个可选值:
SOURCE 表示只在源代码可见,编译的时候就会被丢弃。
CLASS 表示在class可见,也就是说编译的时候可见,但是运行时候不可见。
RUNTIME 表示运行时候可见。什么时候才需要运行时可见呢?那就是使用到反射的时候。我们会在后面的例子中具体的描述这种情况。
Retention本身也是一个注解:
  1. @Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Retention {    /**     * Returns the retention policy.     * @return the retention policy     */    RetentionPolicy value();}
复制代码
Target

Target表示这个注解将会用到什么地方。它有12个值。
TYPE 表示用在Class,interface,enum或者record上。
FIELD 表示用在class的字段上。
METHOD 表示用在方法上。
PARAMETER 表示用在方法上面。
CONSTRUCTOR 用在构造函数上。
LOCAL_VARIABLE 用在本地变量上。
ANNOTATION_TYPE 用在注解上。
PACKAGE 用在package上。
TYPE_PARAMETER 用在类型参数上。
TYPE_USE 用在任何TYPE使用上。
TYPE_PARAMETER和TYPE_USE有什么区别呢?
TYPE_USE用在任何类型的使用上面,比如申明,泛型,转换:
  1. @Encrypted String dataList stringsMyGraph = (@Immutable Graph) tmpGraph;
复制代码
而TYPE_PARAMETER用在类型参数上:
  1. class MyClass {...}
复制代码
MODULE 用在module上。
RECORD_COMPONENT 预览功能,和records相关。
Target和Retention一样也是一个注解。
  1. @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();}
复制代码
自定义参数

注解也可以自定参数,参数可以是下的类型:

  • 基础类型:int,long,double等
  • String
  • Class
  • 枚举类型
  • 其他的注解类型
  • 上面5中的数组
上面我们的自定义类型定义了三个参数:
  1.     int value();    String name();    String[] addresses();
复制代码
我们看下怎么使用:
  1. @CustUserAnnotation(value = 100, name="jack ma",addresses = {"人民路","江西路"})public class CustUser {}
复制代码
在使用中,我们需要传入自定义的参数,当然你也可以使用default在注解中提供默认值,这样就不需要从外部传入。
在运行时使用注解

在运行时,我们可以使用反射的API来获得注解,并获取注解中的自定义变量,从而进行相应的业务逻辑处理。
  1. CustUser custUser= new CustUser();        Annotation[] annotations= custUser.getClass().getAnnotations();        Stream.of(annotations).filter(annotation -> annotation instanceof CustUserAnnotation)                .forEach(annotation -> log.info(((CustUserAnnotation) annotation).name()));
复制代码
还是刚才的例子,我们通过getAnnotations方法获取到注解的值。
在运行时是用注解当然是个不错的主意,但是反射用的太多的话其实会影响程序的性能。
那么我们可以不可以将运行时的注解提前到编译时呢?答案是肯定的。
在编译时使用注解

要想在编译时使用注解,就要介绍今天我们的最后一部分内容annotation processors。
自定义processors需要实现javax.annotation.processing.Processor接口。
接下来我们自定义一个Processor:
[code]@SupportedAnnotationTypes("com.flydean.*")@SupportedSourceVersion(SourceVersion.RELEASE_14)public class MyProcessor extends AbstractProcessor {    @Override    public boolean process(Set
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|冀教网 - 河北教师网站 - 专注于冀教版课本资源  

GMT+8, 2020-6-3 17:51 , Processed in 0.304396 second(s), 29 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表