一 簡介
在上一篇文章中,google-auto之自動生成組件化文件 ,我是簡單的介紹了google的開源框架auto,其中官方的文章中,也有這麼一句話:
其實,auto的內部核心就是使用了註解處理器這個強大的jdk自帶的開源工具來實現對應類或者配置文件生成的。一番學習之後,本來自己想寫一些關於註解處理器的原理和基本的使用,但是看到網上有一篇寫的很不錯,特來記錄。
地址:【Annotation】Processing-Tool詳解
(似乎這篇文章也是該作者轉載)
二 正文
1. 概念
在開始之前,我們需要聲明一件重要的事情是:我們不是在討論在運行時通過反射機制運行處理的註解,而是在討論在編譯時處理的註解。
註解處理器是 javac 自帶的一個工具,用來在編譯時期掃描處理註解信息。你可以爲某些註解註冊自己的註解處理器。註解處理器在Java 5 的時候就已經存在了,但直到 Java 6 (發佈於2006年十二月)的時候纔有可用的API。過了一段時間java的使用者們才意識到註解處理器的強大。所以最近幾年它纔開始流行。
一個特定註解的處理器以 java 源代碼(或者已編譯的字節碼)作爲輸入,然後生成一些文件(通常是.java文件)作爲輸出。那意味着什麼呢?你可以生成 java 代碼!這些 java 代碼在生成的.java文件中。因此你不能改變已經存在的java類,例如添加一個方法。這些生成的 java 文件跟其他手動編寫的 java 源代碼一樣,將會被 javac 編譯。
2.Processor
註解處理器的核心API就是Processor,但是我們在自己實現註解處理器的時候並不是實現Processor,而是實現它的抽象類AbstractProcessor 。Processor類是在rt.jar下,javax.annotation.processing包中
2.1 註解處理器的運行
註解處理器是運行在編譯中,當一個含有註解處理器的jar包被引入到另一個jar包時,進行編譯jar包的過程中,這個時候的註解處理器就進行執行。
2.2 註解處理器的定義
Processor的api文檔中,有這麼一句話,意思是Processor的發現是由一些工具來查找,並決定是否應該運行它們,對於JavaCompiler 編譯而言,你可以通過javax.tools.JavaCompiler.CompilationTask的setProcessos 方法來注入對應的註解處理器,同時你也可以使用ServiceLoad SPI 查找指定目錄下你聲明的註解處理器。如何聲明你的註解處理器呢?
首先,你必須提供一個jar文件,就像其他jar文件一樣,你將你已經編譯好的註解處理器打包到此文件中,並且,你的jar文件中,你必須打包一個特定的文件META-INF/services/javax.annotation.processing.Processor
util-processor.jar
-com
-zcswl
-processor
-ExampleAbstractProcessor.class
-META-INF
-services
-javax.annotation.processing.Processor
其中,javax.annotation.processing.Processor文件中就是你自己定義的註解處理器
com.zcswl.processor.ExampleAbstractProcessor
3.代碼
代碼演示之前,我們首先要去理解Processor中的幾個重要的接口,並理解對應接口的參數,參考對應的AbstractProcessor類
- init(ProcessingEnvironment processingEnv):所有的註解處理器類都必須有一個無參的構造函數,然而,有一個特殊的方法init(),它會被註解處理器調用,ProcessingEnvironment提供了一些實用的工具類Elements,Types和Filer。
- process(Set<? extends TypeElement> annoations, RoundEnvironment env):這類似於每個處理器的main()方法。你可以在這個方法裏面編碼實現掃描,處理註解,生成 java 文件。使用RoundEnvironment 參數,你可以查詢被特定註解標註的元素(原文:you can query for elements annotated with a certain annotation )。
- getSupportedAnnotationTypes():在這個方法裏面你必須指定哪些註解應該被註解處理器註冊。注意,它的返回值是一個String集合,包含了你的註解處理器想要處理的註解類型的全稱。換句話說,你在這裏定義你的註解處理器要處理哪些註解。
- getSupportedSourceVersion():用來指定你使用的 java 版本。通常你應該返回SourceVersion.latestSupported() 。不過,如果你有足夠的理由堅持用 java 6 的話,你也可以返回SourceVersion.RELEASE_6。我建議使用SourceVersion.latestSupported()。在 Java 7 中,你也可以使用註解的方式來替代重寫getSupportedAnnotationTypes() 和 getSupportedSourceVersion()
關於註解處理器代碼的實現可以參考
google-auto:https://github.com/google/auto