Android框架式編程之JavaPoet框架

1、JavaPoet 介紹

JavaPoet是Square推出的開源Java代碼生成框架,提供Java Api生成.java源文件。這個框架功能很是有用,咱們能夠很方便的使用它根據註解、數據庫模式、協議格式等來對應生成代碼。經過這種自動化生成代碼的方式,可讓咱們用更加簡潔優雅的方式要替代繁瑣冗雜的重複工做。

代碼生成技術至關於元編程,可用於編譯期根據註解等元數據動態生成Java類。普遍使用的Dagger,ButterKnife框架就是利用JavaPoet對注入註解生成所需類。java

項目主頁:https://github.com/square/javapoetgit

2、JavaPoet 關鍵類說明

JavaPoet中,有如下幾個關鍵類:github

JavaFile:用於構造輸出包含一個頂級類的Java文件,是對.java文件的抽象。數據庫

TypeSpec:TypeSpec是類/接口/枚舉的抽象。編程

MethodSpec:MethodSpec是方法/構造函數的抽象。緩存

FieldSpec:FieldSpec是成員變量/字段的抽象。框架

ParameterSpec:ParameterSpec用於建立參數。ide

AnnotationSpec:AnnotationSpec用於建立註解。函數

在JavaPoet中,全部Java文件的抽象元素都定義了emit方法,如TypeSepc,ParameterSepc等,emit方法傳入CodeWriter對象輸出字符串。上層元素調用下層元素的emit方法,如JavaFile的emit方法調用TypeSpec的emit方法,從而實現整個Java文件字符串的生成。工具

3、JavaPoet 的使用方式

首先須要引入庫:

compile 'com.squareup:javapoet:1.13.0'

通常狀況下,還須要配合註解解釋器來使用才行,通常咱們經常使用的或註解解釋器爲 AutoServicegradle-incap-helper

這裏咱們以JavaPoet + AutoService來舉例,講解一下如何使用JavaPoet自動生成代碼。

1. 配置 AutoService 的庫

annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'

2. 編寫註解解釋器代碼

@AutoService(Processor.class)
@SupportedAnnotationTypes(Constant.ANY_TYPE)
public class CustomProcessor extends AbstractProcessor {

    private Filer filer;   // 文件生成器

    /**
     *  初始化方法
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        filer = processingEnvironment.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();

        TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                .addMethod(main)
                .build();

        JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld).build();

        try {
            javaFile.writeTo(filer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.RELEASE_7;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return super.getSupportedAnnotationTypes();
    }
}

3. Build項目

完成Build後,就去Build 文件下查找生成的代碼,而後咱們就看到:

生成的代碼內容爲咱們指望的內容:

package com.example.helloworld;

import java.lang.String;
import java.lang.System;

public final class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, JavaPoet!");
  }
}

至此,JavaPoet 的簡單使用方式,咱們就講完了。感興趣的能夠進一步研讀其代碼進行進一步的理解。

4、JavaPoet 框架使用場景

早期的EventBus和ButterKnife都是經過註解並收集緩存相關的類&方法,而後使用時經過反射的方式進行調用,這樣實現雖然功能使用方面沒問題,可是在性能上會由於反射機制爲核心致使性能瓶頸。

在後續的EventBus和ButterKnife的大改版中,對此都進行了優化,經過查看EventBus和ButterKnife項目的源碼,咱們能夠發現它們不約而同地都使用到了JavaPoet來進行代碼的自動生成,進而經過編譯期代碼自動生成的方式避免在運行時的反射調用,進而優化性能體驗。目前二者對應的註解解釋器都是 gradle-incap-helper

在開發的時候,當咱們須要實現一些對性能要求較高的框架或邏輯的時候,動態生成Java代碼技術是替代運行時反射技術的一個很好的選項。

5、知識延申 - 註解處理器

註解處理器(Annotation Processor)是javac的一個工具,它用來在編譯時掃描和處理註解(Annotation)。你能夠自定義註解,並註冊相應的註解處理器(自定義的註解處理器需繼承自AbstractProcessor)。

示例以下所示:

package com.example;

public class MyProcessor extends AbstractProcessor {

    @Override
    public synchronized void init(ProcessingEnvironment env){ }

    @Override
    public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { }

    @Override
    public Set<String> getSupportedAnnotationTypes() { }

    @Override
    public SourceVersion getSupportedSourceVersion() { }

}
  • init(ProcessingEnvironment env): 每個註解處理器類都必須有一個空的構造函數。然而,這裏有一個特殊的init()方法,它會被註解處理工具調用,並輸入ProcessingEnviroment參數。ProcessingEnviroment提供不少有用的工具類如Elements, Types和Filer等。
  • process(Set< ? extends TypeElement> annotations, RoundEnvironment env): 這至關於每一個處理器的主函數main()。你在這裏寫你的掃描、評估和處理註解的代碼,以及生成Java文件。輸入參數RoundEnviroment,可讓你查詢出包含特定註解的被註解元素。
  • getSupportedAnnotationTypes(): 這裏你必須指定,這個註解處理器是註冊給哪一個註解的。注意,它的返回值是一個字符串的集合,包含本處理器想要處理的註解類型的合法全稱。
  • getSupportedSourceVersion(): 用來指定你使用的Java版本。一般這裏返回SourceVersion.latestSupported()。

須要注意的是:註解處理器是運行在獨立的虛擬機JVM中,javac啓動一個完整Java虛擬機來運行註解處理器。

相關文章
相關標籤/搜索