注解處理器(Annotation Processor 是javac的一個工具,它是在編譯時掃描注解和處理注解(Annotation)
可以自定義注解,并注冊相應的注解處理器
在Andorid開源庫中,有不少是使用到注解處理器的框架,像 Butterknife
,Dagger2
和路由ARouter
等等
依賴添加
隨著 Android Gradle 插件 2.2 版本的發布, android-apt
作者聲明后續將不會繼續維護android-apt
,推薦使用 Android 官方插件提供的Android Gradle 插件的 annotationProcessor
功能來完全代替它
Android Gradle 插件 2.2 版本前:
//整個項目的build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
//APP的build.gradle中
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
...
dependencies {
...
apt 'xx.xxx: xxx:1.0.0' //使用apt依賴項目
}
Android Gradle 插件 2.2 版本之后: 使用annotationProcessor 添加依賴項目
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])'
...
annotationProcessor project(':router-compiler')
}
創建相應的模塊
名字隨便起
1.創建一個annotation的java模塊,創建需要用到的注解
比如:這里創建了兩個注解:
@Target({ElementType.TYPE}) //注解使用范圍,在class類上面使用
@Retention(RetentionPolicy.CLASS) //注解生命周期
public @interface Route {
}
2.創建一個compiler的java模塊,在這個模塊自定義注解處理器
這里自定義了一個對應上面Route
注解的注解處理器RouteProcessor
@AutoService(Processor.class) //自動注冊
@SupportedOptions(Consts.ARGUMENTS_NAME) //處理器接受參數
@SupportedSourceVersion(SourceVersion.RELEASE_7) //指定java版本
@SupportedAnnotationTypes({Consts.ANN_TYPE_ROUTE}) //處理的注解
public class RouteProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//編譯期掃碼到注解會調用到這里,在這里處理自動生成代碼
return false;
}
}
@SupportedAnnotationTypes
注冊給哪些注解使用的?等于AbstractProcessor#getSupportedAnnotationTypes() 方法
@SupportedSourceVersion
指定使用的Java版本AbstractProcessor#getSupportedSourceVersion()方法
@SupportedOptions
處理器接收的參數 替代 AbstractProcessor#getSupportedOptions()方法
@AutoService(Processor.class)
自動注冊注解處理器
注解處理器是需要注冊才會被識別使用的,所以需要在這個模塊下添加google自動注冊服務依賴, 如下:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.google.auto.service:auto-service:1.0-rc2' //自動注冊注解處理器
implementation 'com.squareup:javapoet:1.7.0' //javapoet代碼生成框架
implementation project(':router-annotation') //依賴注解模塊
}
當編譯期掃描到注解,就會調用RouteProcessor
的process
方法里面,在這里面處理自動生成代碼的邏輯,可以使用javaPoet
框架來處理需要生成的代碼格式.
JavaPoet是square推出的開源java代碼生成框架,提供Java Api生成.java源文件
@AutoService(Processor.class)
@SupportedOptions(Consts.ARGUMENTS_NAME)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({Consts.ANN_TYPE_ROUTE})
public class RouteProcessor extends AbstractProcessor {
private Filer filer;
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnv.getFiler();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
MethodSpec main = MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class, "args")
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.build();
// HelloWorld class
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
try {
// build com.example.HelloWorld.java
JavaFile javaFile = JavaFile.builder("com.example", helloWorld)
.addFileComment(" This codes are generated automatically. Do not modify!")
.build();
// write to file
javaFile.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
生成的java文件會在使用該注解Route
的模塊下的build目錄下面:
生成.java內容如下:
package com.example;
import java.lang.String;
import java.lang.System;
public final class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, JavaPoet!");
}
}
這是一個簡單的例子
apt注解處理器在項目的應用例子:
做一個自己簡單的Router路由
更多使用的技巧可參考javapoet 的github:
https://github.com/square/javapoet#s-for-strings