平時作項目中有個很是好用的一個插件,叫lombok.它提供了一些簡單的註解,能夠用來生成javabean和一些getter/setter方法,提升了開發的效率節省了開發時間.
今天咱們就來看看lombok使用的什麼方式來實現這種操做的.其實lombok使用的是annotation processor,這個是jdk1.5中增長的新功能.像@Getter只是一個註解,它真正的處理部分
是在註解處理器裏面實現的.官方參考連接.html
註解處理器其實全稱叫Pluggable Annotation Processing API,插入式註解處理器,它是對JSR269提案的實現,具體能夠看連接裏面的內容,JSR269連接.
它是怎麼工做的呢?能夠參考下圖:
1.parse and enter:解析和輸入,java編譯器這個階段會把源代碼解析生成AST(抽象語法分析樹)
2.annotation processing:註解處理器階段,此時將調用註解處理器,這時候能夠校驗代碼,生成新文件等等(處理完能夠循環到第一步)
3.analyse and generate:分析和生成,此時前兩步完成後,生成字節碼(這個階段進行了解糖,好比類型擦除)
這些其實只是爲了給你們留有一個粗淺的印象,它是怎麼執行的.java
看了上面的資料,大腦中應該有了一個大概的印象,如今咱們實際操做一下寫一個簡單的例子,實踐一下.
要使用註解處理器須要兩個步驟:
1.自定義一個註解
2.繼承AbstractProcessor而且實現process方法git
咱們接下來寫一個很簡單的例子,就是在一個類上加上@InterfaceAnnotation,編譯的時候去生成一個"I"+類名的接口類.
首先我這裏是定義了兩個moudle,一個用來寫註解和處理器,另外一個用來調用註解.github
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface InterfaceAnnotation { }
1.@Target:表示的是這個註解在什麼上面使用,這裏ElementType.TYPE是指在類上使用該註解
2.@Retention:表示的是保留到什麼階段,這裏RetentionPolicy.SOURCE是源代碼階段,編譯後的class上就沒有這個註解了apache
@SupportedAnnotationTypes(value = {"com.example.processor.InterfaceAnnotation"}) @SupportedSourceVersion(value = SourceVersion.RELEASE_8) public class InterfaceProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { Messager messager = processingEnv.getMessager(); messager.printMessage(Diagnostic.Kind.NOTE, "進入到InterfaceProcessor中了~~~"); // 將帶有InterfaceProcessor的類給找出來 Set<? extends Element> clazz = roundEnv.getElementsAnnotatedWith(InterfaceAnnotation.class); clazz.forEach(item -> { // 生成一個 I + 類名的接口類 String className = item.getSimpleName().toString(); className = "I" + className.substring(0, 1) + className.substring(1); TypeSpec typeSpec = TypeSpec.interfaceBuilder(className).addModifiers(Modifier.PUBLIC).build(); try { // 生成java文件 JavaFile.builder("com.example.processor", typeSpec).build().writeTo(new File("./src/main/java/")); } catch (IOException e) { e.printStackTrace(); } }); return true; } }
1.@SupportedAnnotationTypes:表示這個processor類要對什麼註解生效
2.@SupportedSourceVersion:表示支持的java版本
3.annotations:被要求的註解,就是@SupportedAnnotationTypes對應的註解
4.roundEnv:存放着當前和上一輪processing的環境信息
5.TypeSpec這個可能有點沒看懂是幹嗎的,它是javaPoet中的一個類,javaPoet是java用於生成java文件的一款第三方插件很好用,因此這裏使用了這個類來生成java文件,
實際上這裏用java自帶的PrintWriter等輸入輸出流也能夠生成java文件,生成文件有不少方式.javaPoet的連接.javaPoet使用指南.
6.Messager是用來打印輸出信息的,System.out.println其實也能夠;
7.process若是返回是true後續的註解處理器就不會再處理這個註解,若是是false,在下一輪processing中,其餘註解處理器也會來處理改註解.api
寫好以後,這裏須要指定processor,META-INF/services/javax.annotation.processing.Processor 寫好com.example.processor.InterfaceProcessor.若是你不知道這是啥,能夠看下我另外一篇博客(實力推廣XD)什麼是SPI
咱們在把註解處理器給編譯好,maven裏插件的設置:oracle
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>1.8</source> <target>1.8</target> <!-- 不加這一句編譯會報找不到processor的異常--> <compilerArgument>-proc:none</compilerArgument> </configuration> </plugin>
此時的目錄結構是這樣:maven
. ├── HELP.md ├── pom.xml ├── processor.iml └── src └── main ├── java │ └── com │ └── example │ └── processor │ ├── InterfaceAnnotation.java │ └── InterfaceProcessor.java └── resources └── META-INF └── services └── javax.annotation.processing.Processor
而後mvn clean install.ide
在使用以前呢,註解處理器要是編譯好的.引入註解處理器的jar包.
測試類加上@InterfaceAnnotationpost
@InterfaceAnnotation public class TestProcessor { }
maven指定編譯時使用的註解處理器.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> <annotationProcessors> <annotationProcessor> com.example.processor.InterfaceProcessor </annotationProcessor> </annotationProcessors> </configuration> </plugin>
此時目錄結構是
. ├── HELP.md ├── pom.xml ├── src │ └── main │ ├── java │ │ └── com │ │ └── example │ │ └── test │ │ └── TestProcessor.java │ └── resources └── test.iml
而後mvn compile,生成了java文件,此時目錄結構是:
. ├── HELP.md ├── pom.xml ├── src │ └── main │ ├── java │ │ └── com │ │ └── example │ │ ├── processor │ │ │ └── ITestProcessor.java // 這裏就是生成的java文件 │ │ └── test │ │ └── TestProcessor.java │ └── resources ├── target │ ├── classes │ │ └── com │ │ └── example │ │ └── test │ │ └── TestProcessor.class │ ├── generated-sources │ │ └── annotations │ └── maven-status │ └── maven-compiler-plugin │ └── compile │ └── default-compile │ ├── createdFiles.lst │ └── inputFiles.lst └── test.iml
看到了生成的java文件就大功告成~
1.java註解處理器在不少地方均可以使用,實際應用好比lombok,安卓生成fragment等等,只使用一個註解能夠省去不少代碼,提升效率;
2.本文只是列舉了一個很簡單的例子,不少註解處理器裏面的api都沒有使用到,讀者有興趣的能夠自行研究,並且有涉及到抽象語法樹的api;
3.註解處理器能夠用於生成新的類來完成某些功能,可是不能直接修改當前的類.
1.https://docs.oracle.com/javas...
2.https://jcp.org/aboutJava/com...
3.https://github.com/square/jav...
4.https://www.cnblogs.com/throw...
5.http://notatube.blogspot.com/...
6.https://www.baeldung.com/java...
7.http://hannesdorfmann.com/ann...