APT-編譯期解析註解

簡介

APT即Annotation Processing Tool,它的做用是在項目編譯期間解析代碼中的註解,經過獲取註解的信息,配合代碼生成工具生成java文件。當項目中有書寫大量相同功能重複代碼的需求時,能夠經過APT進行AOP編程。如ButterKnife EventBus3都是經過APT技術實現的java

自定義註解處理器

新建module,類型選擇java-lib,建立Java類並繼承AbstractProcessor. 這裏有幾個重要的方法須要重寫編程

  1. SourceVersion getSupportedSourceVersion() 用來指定你使用的Java版本。一般這裏返回SourceVersion.latestSupported()
@Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
複製代碼
  1. Set getSupportedAnnotationTypes() 返回類的全路徑集合,表示處理器須要處理的註解集合
@Override
    public Set<String> getSupportedAnnotationTypes() {
        HashSet<String> supportTypes = new HashSet<>();
        supportTypes.add(AnnotationA.class.getCanonicalName());
        supportTypes.add(AnnotationB.class.getCanonicalName());
        return supportTypes;
    }
複製代碼
  1. void init(ProcessingEnvironment processingEnvironment) 註解處理器的初始化階段,能夠經過該方法獲取處理註解和生成Java文件的工具類
private Filer mFilerUtils;       // 文件管理工具類,能夠用於生成java源文件
    private Types mTypesUtils;    // 類型處理工具類,
    private Elements mElementsUtils;  // Element處理工具類,獲取Element的信息
    private Messager mMessager;  //用於打印信息

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        mFilerUtils = processingEnvironment.getFiler();
        mTypesUtils = processingEnvironment.getTypeUtils();
        mElementsUtils = processingEnvironment.getElementUtils();
        mMessager = processingEnvironment.getMessager();
    }
複製代碼
  1. boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)是註解處理器必須實現的方法,全部獲取註解信息和生成Java文件的邏輯都在這裏實現,方法會兩個參數set和roundEnvironment,咱們能夠經過這兩個參數的api獲取註解類的信息
@Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        //遍歷項目工程,找出全部註解AnnotationA的元素
        Set<? extends Element> annotationA =  roundEnvironment.getElementsAnnotatedWith(AnnotationA.class);
        return false;
    }
複製代碼

註解解析時經常使用接口

  • Element

element是表明程序的一個元素,這個元素能夠是:包、類/接口、屬性變量、方法/方法形參、泛型參數。element是java-apt(編譯時註解處理器)技術的基礎,所以若是要編寫此類框架,熟悉element是必須的。api

查看接口源碼框架

public interface Element extends AnnotatedConstruct {
    //返回一個TypeMirror是元素的類型信息,包括包名,類(或方法,或參數)名/類型
    //在生成動態代碼的時候,咱們每每須要知道變量/方法參數的類型,以便寫入
    //正確的類型聲明
    TypeMirror asType();
    //返回註解應用到元素的種類,包括包,類,方法,參數,變量等
    ElementKind getKind();
    //獲取修飾符 public static final等關鍵字
    Set<Modifier> getModifiers();
    //獲取名字,不帶報名
    Name getSimpleName();
    //返回外層的元素
    Element getEnclosingElement();
    //返回該元素直接包含的子元素,一般對一個PackageElement而言,它能夠包含Type
    //Element;對於一個TypeElement而言,它可能包含屬性VariableElement
    //方法ExecutableEleme
    List<? extends Element> getEnclosedElements();

    boolean equals(Object var1);

    int hashCode();
    //獲取該元素上的註解的類型信息,AnnotationMirror相似於TypeMirror
    List<? extends AnnotationMirror> getAnnotationMirrors();
    //根據傳入的註解類型獲取該元素上的註解
    <A extends Annotation> A getAnnotation(Class<A> var1);

    <R, P> R accept(ElementVisitor<R, P> var1, P var2);
}
複製代碼

element的子接口有,也是就是源碼中getKind()能夠獲取的類型ide

  1. packageElement 表示包
  2. TypeElement 表示類,接口,註解
  3. VariableElement 表示變量,參數
  4. TypeParameterElement 表示泛型
  5. ExecutableElement 表示方法體

element所表明的元素只在編譯期可見,用於保存元素在編譯期的各類狀態。工具

  • TypeMirror typeMirror表示的是java層面的類型
@AnnotaionA
int A = 0;
複製代碼

此時VariableElement A元素能夠經過asType,返回對應的java層面int相關的類型信息ui

註冊processor

自定義的Processor須要將它註冊給java編譯器,編譯期在編譯時才能識別。 在src/main目錄下建立resources/META-INF/services/javax.annotation.processing.Processor文件 在javax.annotation.processing.Processor中寫入自定義的Processor的全名(com.xxx.xxx.processor),若是有多個Processor的話,每一行寫一個。spa

配置完成後rebuild項目,就能夠經過process解析註解和生成java文件了code

相關文章
相關標籤/搜索