APT即Annotatino Processing Tool, 他的做用是處理代碼中的註解, 用來生成代碼, 換句話說, 這是用代碼生成代碼的工具, 減小boilerplate代碼.html
咱們經過一個簡單的例子來簡單APT的工做過程, 由於本文demo不設計ide及gradle等, 請注意包名及import問題.java
根據上一篇博客Java中的自定義註解, 首先設計一個自定義註解MyAnnotation
.ide
package com.example; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.SOURCE) // 只保留到編譯階段 @Target(ElementType.TYPE) // 可用於類, 接口.. public @interface MyAnnotation { }
下面來看一下咱們的主角, Processor:工具
package com.example; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.SourceVersion; import javax.lang.model.element.TypeElement; import java.util.HashSet; import java.util.Set; public class MyProcessor extends AbstractProcessor { // Processor初始化回調 @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); System.out.println("MyProcessor init"); } // processor處理過程的回調, 若是須要生成代碼, 就在這個方法中寫. 這個demo暫時不演示代碼生成. @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { System.out.println("process"); return false; } @Override public Set<String> getSupportedAnnotationTypes() { // 在此處聲明該processor支持的註解類型 Set<String> set = new HashSet<>(); set.add(MyAnnotation.class.getCanonicalName()); return set; } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } }
那麼咱們如何把這個apt註冊給javac呢? 咱們將項目以常規的模式打包, 可是在META-INF目錄中加入一個services
文件夾, 在其中建立一個名爲javax.annotation.processing.Processor
的文件, 以文本將processor的完整名字寫進去, 若是有多個processor, 換行便可.測試
javax.annotation.processing.Processor
的內容:gradle
com.example.MyProcessor
最終jar包的結構:設計
mp.jar // jar包名字隨意起 com example MyProcess.class MyAnnotation.class META-INF services javax.annotation.processing.Processor MANIFEST.MF
測試的例子很簡單:code
@MyAnnotation public class Sample { public static void main(String[] args) { System.out.printf("Hello, World!"); } }
咱們用javac
編譯這個文件htm
$ javac -cp mp.jar Sample.java MyProcessor init process process
能夠看到, 咱們的Process已經生成了, 可是process過程輸出了兩次, 緣由能夠參考下圖:blog
process
的過程會進行兩邊, 咱們代碼生成的過程應該在第一遍, 由於第二次processor的過程應當負責作一些清理的工做, 某些打包工具可能不會編譯在第二階段生成的.java源文件.
if (!roundEnv.processingOver()) { ... }