apt流程的介绍

一、 注解

1. 元注解

一共有4个,常用的时候下面两个

@Target、@Rentention、@Documented、@Inherited

  1. @Target

    用来约束注解可以应用的地方(如方法、类、字段),比较常用的有下面几个

    1. TYPE:作用对象类、接口、枚举
    2. FIELD:成员变量
    3. METHOD:成员方法
    4. PARAMETER:方法参数
    5. ANNOTATION_TYPE:注解的注解
  2. @Rentention

    用来约束注解的生命周期,分别有三个值:

    1. 源码级别(source):被编译器(JVM)丢弃,不会保存在class中
    2. 类文件级别(class):不会加载到JVM中,保留在源码或者class中(默认也是这个)
    3. 运行时级别(runtime):会被JVM保留,通过反射机制读取信息

2. 注解元素

对元素的声明,采用方法的声明方式,例如:String name();

对于没有元素的注解,称为 标记注解

/**
 * @author monk
 * @since 2019-01-22
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    /**
     * 定义注解的属性,这不是方法
     */
    String name(); // 必选注解元素

    int value() default 20; // 有属性就是可选属性
}
  1. 支持的数据类型

    1. 所有基本类型(int,float,boolean,byte,double,char,long,short)
    2. String
    3. Class
    4. enum
    5. Annotation
    6. 上述类型的数组
  2. 快捷方式

    当注解元素是唯一1个需要赋值的,并且限定为vulue(),那么使用时候便可以使用快捷方式,省略key,直接赋值value

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface IntegerVaule{
        int value() default 0;
        String name() default "";
    }
    
    public class QuicklyWay{
    	
        // 当只想给value赋值时,可以使用快捷方式
        @IntegerValue(10)
        public int age;
        
        //当name也需要赋值时必须采用key=value的方式赋值
        @IntegerVaule(value = 10000,name = "MONEY")
        public int money;
    }
    
    
  3. java内置注解

    一共3个:

    @Override
    @Deprecated
    @SuppressWarnings // 有选择的关闭编译器对类、方法、成员变量、变量初始化的警告
    

二、 APT

1. java编译流程

img

processor反正source和compile之间,java解释器在这两者之间工作

apt:annotation processing tool,对source源代码进行检测,找出其中Annotation,按照编写者决定生成源文件(java文件)

2. Processor

// javax.annotation.processing.Processor.java

/**
* 由JVM调用
* processingEnv:javac ProcessingEnvironment
*/
void init(ProcessingEnvironment processingEnv);

/**
* 由JVM调用,执行完init,开始执行process
*
* set:com.mono.annotaton.BindPath
*
* 第2轮筛选其依赖的注解
* roundEnv:[errorRaised=false, rootElements=[com.monk.annotationprocessor.MyGeneratedClass], processingOver=false]
*/
boolean process(Set<? extends TypeElement> annotations,RoundEnvironment roundEnv);

process函数,执行情况,从日志输出可以了解到,该函数会执行3轮

  • set包含的是annotation的注解,在第一轮时候会取出,后面两轮size=0

  • roundEnv是依赖注解使用的module的所有类,第二轮会是自己的注解类,第三轮为空,并把processingOver标记为true

  1. Element:

    实际上,Java 源文件是一种结构体语言,源代码的每一个部分都对应了一个特定类型的 Element ,例如包,类,字段,方法等等:

  2. AbstractProcessor:

    apt:annotation processing tool

    对source源代码进行检测,找出其中Annotation,按照编写者决定生成源文件(java文件)

    public class AptAnnotationProcessor extends AbstractProcessor {
        //...
      
        /** 
         * 节点工具类(类、函数、属性都是节点)
         */
        private Elements mElementUtils;
    
        /** 
         * 类信息工具类
         */
        private Types mTypeUtils;
    
        /**
         * 文件生成器
         */
        private Filer mFiler;
    
        /**
         * 日志信息打印器
         */
        private Messager mMessager;
      
        /**
         * 做一些初始化的工作
         * 
         * @param processingEnvironment 这个参数提供了若干工具类,供编写生成 Java 类时所使用
         */
        @Override
        public synchronized void init(ProcessingEnvironment processingEnv) {
            super.init(processingEnv);
            mElementUtils = processingEnv.getElementUtils();
            mTypeUtils = processingEnv.getTypeUtils();
            mFiler = processingEnv.getFiler();
            mMessager = processingEnv.getMessager();
        }
      
        /**
         * 接收外来传入的参数,最常用的形式就是在 build.gradle 脚本文件里的 javaCompileOptions 的配置
         *
         * @return 属性的 Key 集合
         */
        @Override
        public Set<String> getSupportedOptions() {
            return super.getSupportedOptions();
        }
    
        /**
         * 当前注解处理器支持的注解集合,如果支持,就会调用 process 方法
         *
         * @return 支持的注解集合
         */
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            return super.getSupportedAnnotationTypes();
        }
    		
        /**
         * 编译当前注解处理器的 JDK 版本
         *
         * @return JDK 版本
         */
        @Override
        public SourceVersion getSupportedSourceVersion() {
            return super.getSupportedSourceVersion();
        }
    }
    
    
    1. 注解处理器注册

      自动注册方式:

      1. 在当前module下的build.gradle文件下导入以下依赖

        implementation 'com.google.auto.service:auto-service:1.0-rc6'
        annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'
        

        注意:以上必须同时加,否则注册不成功,我之前也踩过坑

      2. 在注解处理器上加上@AutoService(Processor.class) 即可完成注册

        @AutoService(Processor.class)
        public class AptAnnotationProcessor extends AbstractProcessor {
            //...
        }
        
    2. 注解处理器生成类文件

      通过javapoet框架编写,具体可参考上述链接使用javapoet

    3. 调用生成代码

      编写annotationapi的android module,通过反射api,将生成的Helloworld类进行封装使用即可。

3. ProcessingEnvironment

由JVM初始化,可以获取:

  1. Filer(JavacFiler)文件管理器
  2. Elements,节点工具类(类、函数、属性都是节点)
  3. Types,类信息工具类
  4. Messager,日志信息打印器
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值