Java中的APT注解

java中常用的一些框架都使用到了注解,比如EventBus、Dragger2、Butterknife等,从这些流行框架可以看出,注解在Android中使用还是很广泛的,常见的注解有运行时注解和编译期注解,运行时注解是通过反射在运行时拿到注解信息进行处理,编译期注解是在编译阶段根据注解生成相应的中间类来处理注解,因为运行时注解需要在运行时执行反射代码和注解处理逻辑,所以它的运行时性能没有编译期注解高,本文学习的注解方式就是APT编译时注解。

1、创建一个名称为annotation的module用来单独存放自定义的注解类,然后在该模块下可以新建一个自定义的注解类(这里以HuiAnnotation为例)

/**
 * Created by znh on 2020/7/29
 * 

* 自定义注解 */ @Target(ElementType.TYPE)//作用在类上 @Retention(RetentionPolicy.CLASS)//编译期注解 public @interface HuiAnnotation { }

2、创建一个名称为processor的module用来存放注解处理器,这个模块中需要处理上一步中自定义的注解,所以需要将annotation模块引入进来,自定义的注解处理器需要继承至谷歌注解处理器框架中的AbstractProcessor类,所以需要引入注解处理器框架,为了更好的生成java模板代码,还可以引入javapoet代码模板生成框架(这个不是必须的,使用它可以更方便的生成java代码),以上3个依赖包在gradle中的依赖配置如下:

//添加注解处理器依赖
implementation 'com.google.auto.service:auto-service:1.0-rc6'
//gradle5.0及以上需要
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'

//添加自定义的注解类依赖
implementation project(':annotation')

//用来生成java模板代码的框架
implementation 'com.squareup:javapoet:1.11.1'

然后在该模块下新建一个注解处理器类(这里以HuiProcessor为例),这个自定义的注解处理器类中有几个比较重要的方法需要重写:

  • @AutoService(Processor.class):要为注解处理器添加上这个注解才可以生效
  • init(ProcessingEnvironment processingEnvironment):做一些初始化的操作
  • getSupportedAnnotationTypes():支持的注解有哪些,将自己定义的注解添加进去
  • getSupportedSourceVersion() :支持的jdk版本号
  • process(Set set, RoundEnvironment roundEnvironment):注解处理的核心方法,注解处理逻辑就是在这个方法中写的

注解处理器HuiProcessor的代码如下:

/**
 * Created by znh on 2020/7/29
 * 

* 自定义注解处理器 */ @AutoService(Processor.class) public class HuiProcessor extends AbstractProcessor { private Elements mElementUtils; private Messager mMessager; /** * 做一些初始化操作 * * @param processingEnvironment */ @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); mElementUtils = processingEnvironment.getElementUtils(); mMessager = processingEnvironment.getMessager(); } /** * 支持的注解有哪些 * * @return */ @Override public Set<String> getSupportedAnnotationTypes() { Set<String> annotationTypes = new LinkedHashSet<>(); annotationTypes.add(HuiAnnotation.class.getCanonicalName()); return annotationTypes; } /** * 支持的jdk版本 * * @return */ @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } /** * 注解核心处理方法 * * @param set * @param roundEnvironment * @return */ @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { //没有需要处理的注解 if (set.isEmpty()) return false; //获取项目中使用了HuiAnnotation注解的元素集合 Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(HuiAnnotation.class); //遍历elements for (Element element : elements) { //获取元素的包名 String packageName = mElementUtils.getPackageOf(element).getQualifiedName().toString(); //获取元素的类名 String className = element.getSimpleName().toString(); //自定义需要生成的类文件名称 String customClassName = className + "Helper"; //打印日志 mMessager.printMessage(Diagnostic.Kind.NOTE, "packageName:" + packageName); mMessager.printMessage(Diagnostic.Kind.NOTE, "className:" + className); mMessager.printMessage(Diagnostic.Kind.NOTE, "customClassName:" + customClassName); //创建一个方法参数 ParameterSpec msgParam = ParameterSpec .builder(String.class, "msg") //定义参数类型和参数名称 .build(); //生成方法 MethodSpec print = MethodSpec.methodBuilder("print") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(String.class) .addStatement("$T.out.println($S)", System.class, "Hello," + customClassName)//定义打印语句 .addParameter(msgParam) .addStatement("return $N", msgParam) .build(); //生成类 TypeSpec customClassType = TypeSpec.classBuilder(customClassName) .addModifiers(Modifier.PUBLIC) .addMethod(print) .build(); //生成java文件 JavaFile javaFile = JavaFile.builder(packageName, customClassType).build(); try { javaFile.writeTo(processingEnv.getFiler()); } catch (IOException e) { e.printStackTrace(); } } return true; } }

3、这个注解处理器的作用是生成一个类名为自定义的customClassName中间辅助类,在这个类中生成一个能打印信息的方法。注解和注解处理器定义完成之后就可以在项目中使用了,在app的module中使用时需要将注解和注解处理器依赖进去,gradle配置如下:

implementation project(':annotation')
annotationProcessor project(':processor')

然后在需要的类上添加注解并编译项目,会生成一个中间辅助类:
Java中的APT注解_第1张图片
然后可以调用生成的中间辅助类的方法去完成自己的业务逻辑了,使用代码如下:

package com.znh.aptdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.znh.annotation.HuiAnnotation;

@HuiAnnotation //为MainActivity添加注解
public class MainActivity extends AppCompatActivity {
     

    @Override
    protected void onCreate(Bundle savedInstanceState) {
     
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        test();
    }

    public void test() {
     
    	//调用中间类的方法进行测试
        String msg = MainActivityHelper.print("测试一下...");
        System.out.println(msg);
    }
}

打印结果如下:
13077-13077/com.znh.aptdemo I/System.out: Hello,MainActivityHelper
13077-13077/com.znh.aptdemo I/System.out: 测试一下...

Demo地址:https://github.com/huihuigithub/blog_demo_projects (java_apt_demo项目)

你可能感兴趣的:(Android,注解,apt,android)