Retrofit解析4之注解

作者: 隔壁老李头 | 来源:发表于2017-06-27 22:17 被阅读557次

    整体Retrofit内容如下:

    由于Retrofit里面大量的用到了注解,为了让大家更好的学习Retrofit,特意准备了一篇Java注解,如果大家已经对Java注解已经很熟悉了,就略过,看下一篇文章
    本篇文章主要讲解

    • 1、Java 注解技术基本概念
    • 2、Java 元注解
    • 3、标准注解/内建注解
    • 4、自定义注解
    • 5、注解处理器
    • 6、注解思维导图
    • 7、注解原理

    一、Java注解技术基本概念

    (一) 什么是注解

    Annotation是java 5开始引入的新特征。中文名称一般叫注解。它提供了一种安全的类似于注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。

    上面的类似官方的解释,那我们再来通俗的解释一下:
    我们都知道在Java代码中使用注解是为了提升代码的可读性,也就是说,注释是给人看的(对编译器来说是没有意义上的)。注解可以看做注释的"加强升级版",它可以向编译器、虚拟机等解释说明一些事情(也就是说它对编译器等工具也是"可读"的)。比如我们非常熟悉的@Overrider 注解,它的作用是告诉编译器它所注解的方法是重写父类中的方法,这样编译器就会检查父类是否存在这个方法,以及这个方法的签名与父类是否相同。
    也就是说,注解是描述Java代码的代码,它能够被编译器解析,注解处理工具在运行时也能够解释注解。除了向编译器等传递一些信息,我们也可以用注解生成代码。比如我们可以用注解描述我们的意图,然后让注解解析工具来解析注解,以此来生成一些"模板化"的代码。注解是一种"被动"的信息,必须有编译器或虚拟机来"主动"解析它,它才能发挥自己的作用。

    (二) 什么是元数据(metadata)

    元数据由metadata翻译来的,所谓元数据就是"关于数据的数据",更通俗的说就是描述数据的数据的,对数据及信息资源的描述性信息,比如一个文本文件,有创建时间、创建人、文件大小等数据,都是可以理解为是元数据。在java中,元数据以标签的形式存在java代码中,它的存在并不影响程序代码的编译和执行,通常它被用来生成其他的文件或运行时知道被运行代码的描述信息。java代码中的javadoc和注解都属于元数据。

    (三) 注解的前世今生

    注解首先在第三版的Java Language Specification中被提出,并在Java 5中被实现。

    (四)为什么要使用注解

    • 1、在未使用Annotation之前(甚至是使用之后),一般使用XML来应用于元数据的描述。不是何时开始一些开发人员和架构师发现XML的维护原来越复杂和糟糕,他们希望使用一些和代码紧密耦合的东西,而不是像XML一样是松耦合的(在某些情况下甚至是完全分离的)代码描述。如果你在百度或者google中搜索"xml vs annotations",就会看到关于这个话题的辩论。因为XML的配置就是为了分离代码和配置而设置的。但是用Annotation(注解)还是XML各有利弊。(下面有举例说明)
    • 2、另外一个很重要的因素是Annotation注解定义一种标准的描述元数据的方式。在这之前,开发者通常使用他们自己的方式定义元数据。例如,使用标记interface,注释,transient关键字等。每个程序员都用自己的方式定义元数据,而不像Annotation这种标准的方式。

    下面我简单举例说明。
    比如,你想为你的应用设置很多常量或参数,这种情况下,XML是一个很好的选择,因为它不会与特定的代码关联。如果你想把某个方法声明为服务,那么使用Annotation会更好一些,因为这种情况下需要注解和方法高度耦合一起。

    因为XML是松耦合的,注解是紧耦合的,所以目前主流的框架将XML和Annotation两种方式结合使用,平衡两者之前的利弊。
    在需要高度耦合的地方,Annotation注解比XML更容易维护,阅读更方便
    在需要松耦合的地方,使用XML更方便
    在某个方法声明为服务时,这种紧耦合的情况下,比较适合Annation注解。

    (五)、注解的作用

    Annotation 注解 通常被用以作以下目的:

    • 1、编译器指令
    • 2、构建时指令
    • 3、运行时指令
      Java 内置了三种编译器指令,Java注解可以应用于构建时,即当你构建你的项目时,构建的过程包括产生源代码、编译源代码、产生xml文件,将编译过的代码或者文件打包进jar文件等。通常情况下,注解不会出现在编译之后的Java代码中,但是想要出现也是可以的。Java支持运行时注解。这些注解可以通过java反射访问,运行时注解主要是提供给程序或者第三方API一些指令。

    (六) 注解基础

    一个简单的Java注解 类似于下面的这种 @Doctor ,"@" 符号告诉编译器这是一个注解,跟在"@" 符号后面的是注解的名字,上述的例子中注解的名字是Doctor。

    (七) 注解元素

    Java 注解可以使用元素设置一些值,元素类似于属性或者参数。下面是一个包含元素注解的例子

    @Doctor (name = "张三")
    

    上述注解的元素名称是name,值是"张三",没有元素的注解不需要括号。注解可以包含多个元素,下面就是包含多个元素的例子

    @Doctor(name = "张三", sex= "男")
    

    当注解只包含一个元素时,你可以省去写元素的名字,直接赋值即可。下面的例子就是直接赋值。

    @InsertNew("yes")
    

    (八)注解使用

    Annotation 注解可以在以下场合被使用到

    • 接口
    • 方法
    • 方法参数
    • 属性
    • 局部变量

    二、元注解

    (一) 什么是元注解

    元注解,元注解就是负责注解其它注解.Java5.0定义了4个标准的meta-annotation类型,它们呗用来提供对其他annotation类型作说明。Java5.0定义的元注解:

    • @Target
    • @Retention
    • @Documented
    • @Inherited

    这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们来看一下每一个元注解的作用和说明

    1、@Target

    表示该注解可以用在什么地方,由ElementType枚举定义

    • CONSTRUCTOR:构造器的声明
    • FIELD:域声明(包括enum实例)
    • LOCAL_VARIABLE:布局变量声明
    • METHOD:方法声明
    • PACKAGE:包声明
    • PARAMETER:参数声明
    • TYPE:类、接口(包括注解类型)或enum声明
    • ANNOTATION_TYPE:注解声明(应用于另一个注解上)
    • TYPE_PARAMETER:类型参数声明(1.8新加入)
    • TYPE_USE:类型使用声明(1.8新加入)
      PS: 当注解未制定Target值时,此注解可以使用任何元素之上,就是上面的类型。

    举例如下:

    @Target(ElementType.METHOD)
    public @interface MethodInfo { 
    }
    

    上面代码中我们使用"@Target"元注解来说明MethodInfo这个注解只能应用于对方法进行注解。

    2、@Retention

    表示需要在什么级别保存该注解信息,由RetentionPolicy枚举定义

    • SOURCE:注解将编译器丢弃(该类型的注解信息只会保留在源码里,源码经过编译后,注解信息会被丢弃,不会保留在编译好的class文件里)
    • CLASS:注解在class中可用,但会被VM丢弃(该类型的注解信息会保留在源码里和class文件里,在执行的时候,不会加载到虚拟机中(JVM)中)
    • RUNTIME:VM将在运行期也保留注解信息,因此可以通过反射机制读取注解信息(源码、class文件和执行的时候都有注解的信息)

    PS:当胡姐未定义Retention值时,默认值是CLASS

    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    

    这表明@Override 注解只在源码阶段存在,javac在编译过程中去掉该注解。

    3、@Documented

    表示注解会被包含在javaapi文档中
    当一个注解被@Documented元注解所修饰时,那么无论在哪里使用这个注解,都会被Javadoc工具文档化。
    举例如下

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)public @interface Documented {
    }
    

    这个元注解呗@Documented修饰,表示它本身会被文档化。@Retention注解的值RetentionPolicy.RUNTIME表示@Documented这个注解能保留在运行时;@Target元注解的值ElementType.ANNOTATION_TYPE表示@Documented这个注解只能够来修饰注解类型

    4、@Inherited

    允许子类继承父类的注解。
    用于描述某个被标注的类型可被继承的,如果一个使用了@Inherited修饰的annotation类型类型被用于一个class,则这个annotation将被用于该class类的子类。
    表明被修饰的注解类型是自动继承的。如果你想让一个类和它的子类都包含某个注解,就可以使用@Inherited来修饰这个注解。也就是说,假设@Parent类是Child类的父类,那么我们若用被@Inherited元注解所修饰的某个注解对Parent类进行了修饰,则相当于Child类也被该注解所修饰了。这个元注解的定义如下:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)public @interface Inherited {
    }
    
    @Inherited
    public @interface MyAnnotation {
    }
    
    @MyAnnotation
    public class MySuperClass {
    }
    
    public class MySubClass extends MySuperClass {
    }
    

    上述代码的大致意思是使用@Inherited修饰注解MyAnnotation使用MyAnnotation注解MySuperClass实现类MySubclass继承自MySuperClass

    当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

    三、标准注解/内建注解

    Java本身内建了一些注解,用来为编译器提供指令。如下:

    • @Override
    • @Deprecated
    • @SuppressWarnings
      下面让我们详细了解下三个标准注解/内建注解

    1、@Override注解

    @Override注解用来修饰对父类进行重写的方法。如果一个并非重写父类的方法使用这个注解,编译器将提示错误。

    实际上在子类中重写父类或接口的方法,@Overrider并不是必须的。但是还是建议使用这个注解,在某些情况下,假设你修改了父类的方法的名字,那么之前重写子类方法将不再属于重写,如果没有@Override,你将不会觉察到这个子类的方法。有了这个注解修饰,编译器则会提示你这些信息。
    例子如下:

    public class MySuperClass {
    
        public void doTheThing() {
            System.out.println("Do the thing");
        }
    }
    
    
    public class MySubClass extends MySuperClass{
    
        @Override
        public void doTheThing() {
            System.out.println("Do it differently");
        }
    }
    

    2、@ Deprecated

    @Deprecate 标记类、方法、属性,如果上述三种元素不再使用,使用@Deprecated注解,建议用户不再使用

    如果代码使用了@Deprecate 注解的类、方法或属性,编译器会进行警告。
    举例如下:

    @Deprecated
    public class MyComponent {
    }
    

    当我们使用@Deprecate注解后,建议配合使用对应的@deprecated JavaDoc 符号,并解释说明为什么这个类,方法或属性被弃用,已经替代方案是什么?如下:

    @Deprecated
    /**
      @deprecated This class is full of bugs. Use MyNewComponent instead.
    */
    public class MyComponent {
    }
    

    3、@SuppressWarnings

    @SuppressWarnings 用来抑制编译器生成警告信息。可以修饰的元素为类,方法,方法参数,属性,局部变量。

    使用场景:当我们一个方法调用了弃用的方法或者进行不安全的类型转换,编译器会生成警告。我们可以为这个方法增加@SuppressWarnings
    注解,来抑制编译器生成警告。

    PS:使用@SuppressWarnings注解,采用就近原则,比如一个方法出现警告,我们尽量使用@SuppressWarnings注解这个方法,而不是注解方法所在的类。虽然两个都能抑制编译器生成警告,但是范围越小越好,因为范围到了,不利于我们发现该类下其他方法的警告信息。
    举例如下:

    @SuppressWarnings
    public void methodWithWarning() {
    }
    

    四、自定义注解

    1、注解格式

    了解完系统注解之后,我们就可以自己定义注解了,通过上面的@Override的实例,不难看出定义注解的格式如下:

    public @Interface 注解名{定义体}
    

    PS:定义体就是方法的集合,每个方法实则是生命了一个配置参数,方法的名称作为配置参数的名称,方法的返回值类型就是配置参数的类型,和普通的方法不一样,可以通过default关键字来声明配置参数的默认值。
    注意:

    • 1、注解类型是通过"@interface"关键字定义的
    • 2、此处只能使用public或者默认的default两个权限修饰符
    • 3、配置参数的类型只能使用基本类型(byte,boolean,char,short,int,long,float,double和String,Enum,Class,annotation)
    • 4、对于只含有一个配置参数的注解,参数名建议设置中value,即方法名为value.
    • 5、配置参数一旦设置,其参数值必须有确定的值,要不在使用注解的时候指定,要不在定义注解的时候使用default为其设置默认值,对于非基本类型的参数值来说,其不能为null。

    2、创建自己的注解

    在Java中,我们可以创建自己的注解,注解和类,接口文件一样定义在自己的文件里面。如下:

    @interface MyAnnotation {
       String   name();
       int      age();
       String   sex();
     
     
    }
    

    上述代码定义了一个叫做MyAnnotation的注解,它有4个元素。再次强调一下,@Interface 这个关键字 用来告诉java编译器这是一个注解。
    应用举例

    @MyAnnotation(
        name="张三",
        age=18,
        sex="男"
    )
    public class MyClass {
    }
    

    注意,我们需要为所有的注解元素设置值,一个都不能少。

    3、自定义注解默认值

    对于注解总的元素,我们可以为其设置默认值,使用方法如下:

    @interface MyAnnotation {
        String   name();
        int      age();
       String   sex() default "男";
    }
    

    上述代码,我们设置了sex元素的默认值为"男"。当我们在使用时,可以不设置sex的值,即让value使用空字符串默认值。举例如下;

    @MyAnnotation(
        name="Jakob",
        age=37,
    )
    public class MyClass {
    }
    

    五、注解的原理

    1、注解处理器

    如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用户了,使用注解的过程中,很重要的一部分就是创建与使用注解处理器。Java SE 扩展了反射机制的API,以帮助程序员快速的构造自定义注解处理器。

    2、注解处理器的分类

    我们已经知道了如何自定义注解,当时想要注解发挥实际作用,需要我们为注解编写响应的注解处理器,根据注解的特性,注解处理器可以分为运行时注解处理器编译时注解处理器。运行时注解处理器需要借助反射机制实现,而编译时处理器则需要借助APT来实现。

    无论是运行时注解处理器还是编译时注解处理器,主要工作都是读取注解及处理特定主机,从这个角度来看注解处理器还是非常容易理解的。

    3、运行时注解处理器

    熟悉Java反射机制的同学一定对java.lang.reflect包非常熟悉,该包中的所有API都支持读取运行时Annotation的能力,即属性为@Retention(RetentionPolicy.RUNTIME)的注解。

    在Java.lang.reflect中中的AnnotatedElement接口是所有程序元素的(Class、Method)父接口,我们可以通过反射获取到某个类的AnnotatedElement对象,进而可以通过该对象提供的方法访问Annotation信息,常用的方法如下:

    方法 含义
    < T extends Annotation > T getAnnotation(Class <T> annotationClass) 表示返回该元素上存在的定制类型的注解
    Annotation[] getAnnotations() 返回该元素上存在的所有注解
    default <T extends Annotation> T[] getAnnotationsByType(Class <T> annotationClass) 返回该元素制定类型的注解
    default <T extends Annotation> T getDeclaredAnnotation( Class <T> annotationClass) 返回直接存在与该元素上的所有注解
    default <T extends Annotation>T[] getDeclaredAnntationsByType(Class <T> annotationClass) 返回直接存在该元素上某类型的注解
    Annotation[] getDeclaredAnnotations() 返回该元素上的所有注解

    举例说明
    一个User实体类

    public class User {
        private int id;
        private int age;
        private String name;
    
        @UserData(id=1,name="张三",age = 10)
        public User() {
        }
        public User(int id, int age, String name) {
            this.id = id;
            this.age = age;
            this.name = name;
        }
      //...省略setter和getter方法
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", age=" + age +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    

    我们希望可以通过@UserData(id=1,name="张三",age = 10)这个注解,来为设置User实例的默认值。
    自定义注解如下:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.CONSTRUCTOR)
    public @interface UserData {
        public int id() default 0;
        public String name() default "";
        public int age() default 0;
    }
    

    该注解类作用于构造方法,并在运行时存在,这样我们就可以在运行时通过反射获取注解进而为User实例设值,看看如何处理该注解
    运行时注解处理器:

    public class AnnotationProcessor {
    
        public static void init(Object object) {
    
            if (!(object instanceof User)) {
                throw new IllegalArgumentException("[" + object.getClass().getSimpleName() + "] isn't type of User");
            }
    
            Constructor[] constructors = object.getClass().getDeclaredConstructors();
            for (Constructor constructor : constructors) {
                if (constructor.isAnnotationPresent(UserMeta.class)) {
                    UserMeta userFill = (UserMeta) constructor.getAnnotation(UserMeta.class);
                    int age = userFill.age();
                    int id = userFill.id();
                    String name = userFill.name();
                    ((User) object).setAge(age);
                    ((User) object).setId(id);
                    ((User) object).setName(name);
                }
            }
        }
    }
    

    测试代码

    public class Main {
    
        public static void main(String[] args) {
            User user = new User();
            AnnotationProcessor.init(user);
            System.out.println(user.toString());
        }
    }
    

    运行测试代码,便得到我们想要的结果:

    User{id=1, age=10, name=’dong’}
    

    这里通过反射获取User类声明的构造方法,并检测是否使用了@UserData注解。然后从注解中获取参数值并将其复赋值给User对象。
    正如上面所说,运行时注解处理器的编写本质上就是通过反射获取注解信息,随后进行其他操作。编译一个运行时注解处理器就是那么简答。运行时注解通常多用于参数配置模块。

    4、编译时注解处理器

    不同于运行时注解处理器,编写编译时注解处理器(Annotation Processor Tool)。
    APT 用于编译时期扫描和处理注解信息,一个特定的注解处理器可以以Java源文件或编译后的class文件作为输入,然后输出另一些文件,而已是.java文件,也可以是.class文件,但通常我们输出的是.java文件。(注意:并不是对源文件进行修改),这些java文件会和其他源文件一起被javac编译。
    你可能会很纳闷,注解处理器是到底在什么阶段介入的呢?好吧,其实是在javac开始编译之前,这就是通常我们为什么愿意输出.java文件的原因。

    注解最早是在java 5引入的,主要包含APT和com.sum.mirror包中现相关mirror api,此时APT和javac是各自独立的,但是从Java 6开始,注解处理器正式标准化,APT工具也被直接集成在javac当中。

    编译时注解处理器编译一个注解时,主要分2步

    • 1、 继承AbstractProcessor,实现自己的注解处理器
    • 2、注册处理器,并打包成jar

    举例说明:
    首先来看一下一个标准的注解处理器的格式:

    public class MyAnnotationProcessor extends AbstractProcessor {
    
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            return super.getSupportedAnnotationTypes();
        }
    
        @Override
        public SourceVersion getSupportedSourceVersion() {
            return super.getSupportedSourceVersion();
        }
    
        @Override
        public synchronized void init(ProcessingEnvironment processingEnv) {
            super.init(processingEnv);
        }
    
        @Override
        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
            return false;
        }
    }
    

    来简单的了解下其中5个方法的作用

    方法 作用
    init(ProcessingEnvironment processingEnv) 该方法有注解处理器自动调用,其中ProcessingEnvironment类提供了很多有用的工具类:Filter,Types,Elements,Messager等
    getSupportedAnnotationTypes() 该方法返回字符串的集合表示该处理器用于处理那些注解
    getSupportedSourceVersion() 该方法用来指定支持的Java版本,一般来说我们都是支持到最新版本,因此直接返回SourceVersion.latestSupported()即可
    process(Set annotations, RoundEnvironment roundEnv) 该方法是注解处理器处理注解的主要地方,我们需要在这里写扫描和处理注解的代码,以及最终生成的java文件。其中需要深入的是RoundEnvironment类,该用于查找出程序元素上使用的注解

    编写一个注解处理器首先要对ProcessingEnvironment和RoundEnvironment非常熟悉。接下来我们来了解下这两个类,先看下ProcessingEnvironment类:

    public interface ProcessingEnvironment {
    
        Map<String,String> getOptions();
    
        //Messager用来报告错误,警告和其他提示信息
        Messager getMessager();
    
        //Filter用来创建新的源文件,class文件以及辅助文件
        Filer getFiler();
    
        //Elements中包含用于操作Element的工具方法
        Elements getElementUtils();
    
         //Types中包含用于操作TypeMirror的工具方法
        Types getTypeUtils();
    
        SourceVersion getSourceVersion();
    
        Locale getLocale();
    }
    

    重点来认识一下Element,Types和Filer。Element(元素)是什么呢?

    Element

    element表示一个静态的,语言级别的构件。而任何一个结构化文档都可以看作是由不同的element组成的结构体,比如XML,JSON等。这里我们用XML来示例:

    <root>
      <child>
        <subchild>.....</subchild>
      </child>
    </root>
    

    这段xml中包含了三个元素:<root>、<child>、<subchild>到现在你已经明白元素是什么。对java源文件来说,他同样是一种结构化文档:

    package com.demo;             //PackageElement
    public class Main{                  //TypeElement
        private int x;                  //VariableElement
        private Main(){                 //ExecuteableElement
        }
        private void print(String msg){ //其中的参数部分String msg TypeElement
        }
    }
    

    对于java源文件来说,Element代表程序元素:包,类,方法都是一种程序元素。另外如果你对网页解析工具jsoup熟悉,你会觉得操作此处的element是非常容易,关于jsoup不在本文讲解之内。

    接下来看看各种Element之间的关系图,以便有个大概的了解


    element关系图.png
    元素 含义
    VariableElement 代表一个 字段, 枚举常量, 方法或者构造方法的参数, 局部变量及 异常参数等元素
    PackageElement 代表包元素
    TypeElement 代表类或接口元素
    ExecutableElement 代码方法,构造函数,类或接口的初始化代码块等元素,也包括注解类型元

    TypeMirror、TypeElement、DeclaredType 这三个类我也简单的介绍下:

    • TypeMirror:代表Java语言中类型.Types包括基本类型,声明类型,数组,类型变量和空类型。也代表通配类型参数,可执行文件的签名和返回类型等.
    • TypeElement 代表类或接口元素
    • DeclaredType 代表类型或接口类型

    简单的来说,Element代表源代码,TypeElement代表的是源码中的类型元素,比如类,虽然我们可以从TypeElement中获取类名,TypeElement中不包含类本身的信息,比如它的父类,要想获取这信息需要借助TypeMirror,可以通过的Element中的asType()获取元素对应的TypeMirror。

    Filer

    Filter 用于注解处理器中创新文件。

    然后看一下RoundEnvironment这个类,这个类比较简单

    public interface RoundEnvironment {
    
        boolean processingOver();
    
         //上一轮注解处理器是否产生错误
        boolean errorRaised();
    
         //返回上一轮注解处理器生成的根元素
        Set<? extends Element> getRootElements();
    
       //返回包含指定注解类型的元素的集合
        Set<? extends Element> getElementsAnnotatedWith(TypeElement a);
    
        //返回包含指定注解类型的元素的集合
        Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a);
    }
    

    然后来看一下RoundEnvironment,这个类比较简单,一笔带过:
    public interface RoundEnvironment { boolean processingOver(); //上一轮注解处理器是否产生错误 boolean errorRaised(); //返回上一轮注解处理器生成的根元素 Set<? extends Element> getRootElements(); //返回包含指定注解类型的元素的集合 Set<? extends Element> getElementsAnnotatedWith(TypeElement a); //返回包含指定注解类型的元素的集合 Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a);}

    Filer
    Filer用于注解处理器中创建新文件。具体用法在下面示例会做演示.另外由于Filer用起来实在比较麻烦,后面我们会使用javapoet简化我们的操作.
    好了,关于AbstractProcessor中一些重要的知识点我们已经看完了.假设你现在已经编写完一个注解处理器了,下面,要做什么呢? |

    打包并注册.

    自定义的处理器如何才能生效那?为了让Java编译器找到自定义的注解处理器我们需要对其进行注册和打包:自定义的处理器需要被达成一个jar,并且需要在jar包的META-INF/services路径下中创建一个固定的文件
    javax.annotation.processing.processor,在javax.annotation.processing.Processor文件中需要填写自定义处理器的完整路径名,有几个处理器就要填写几个
    从Java 6之后,我们只需要将打开的jar防止到项目的buildpath下即可,javac在运行的过程会自动检查javax.annotation.processing.Processor注册的注解处理器,并将其注册上。而Java 5需要单独使用APT工具。
    最终我们需要获得一个包含注解处理器的代码的jar包

    六、注解基础知识思维导图

    最后借用下别人的Java注解的基础知识点导图


    Java注解.png

    相关文章

      网友评论

      本文标题:Retrofit解析4之注解

      本文链接:https://www.haomeiwen.com/subject/oyoafxtx.html