1.編譯器通常編譯流程html
2.javac的編譯流程是怎樣的前端
3.如何hack掉Java編譯器java
4.運行時DI和編譯期DI的區別node
1.一、通常執行流程
1.二、編譯案例
符號表: 是一種用於數據結構,源程序中的每一個標識符都和它的聲明或使用信息綁定在一塊兒,好比其數據類型、做用域以及內存地址。 在編譯程序工做過程當中,會不斷收集、記錄和使用源程序中一些語法符號的類型和特徵等相關信息,這些信息通常以表格形式存儲於系統中,如常數表、變量表、數組名錶、過程名錶、標號表等,這些統稱爲符號表。
2.一、Java程序編譯執行過程
在前端編譯時,把Java源文件編譯爲Class文件;git
在解釋執行時,會收集運行數據,根據熱點代碼進行JIT編譯優化,生成本地機器碼,加快程序的執行。github
關於類加載器以及系統啓動執行流程:一篇圖文完全弄懂類加載器與雙親委派機制shell
具體的加載Class文件到JVM的流程:一篇圖文完全弄懂Class文件是如何被加載進JVM的apache
3.一、javac中的主要類
3.二、javac主要處理流程
initProcessAnnotations(processors)
:後端準備過程:初始化插入式註解處理器api
Parse
:parseFiles(sourceFileObjects) 解析步驟,讀取一系列的Java源文件,把解析的Token序列結果映射到AST-Nodes(抽象語法樹各個節點):詞法分析
:將字符流轉換爲標記(Token
)集合(符號流);語法分析
:根據token序列構造抽象語法樹,後續操做都創建在抽象語法樹上,語法分析相關類:Parser
;Enter
:enterTrees方法負責填充符號表,編譯器將在其做用域範圍內找到全部定義的符號,主要包含如下兩個階段:第一階段:註冊全部類到其相應的做用域範圍,在這一步編譯器爲每一個類符號記錄一個MemberEnter對象,該對象將用於第二階段;
第二階段:使用上面的MemberEnter對象繼續完善類符號相關信息。主要包括:肯定類的參數,超類和接口。
Annotate
:processAnnotations():註解處理器的執行過程。若是存在註解處理器,而且請求了註解處理,則將處理在指定的編譯單元中找到的全部註解。JSR 269定義了用於編寫此類插件的接口,後面會有詳細介紹。
delegateCompiler.compile2()
:分析及字節碼生成Attribute
:語義分析過程,標註檢查,主要包括諸如變量使用前是否已被聲明、變量與賦值之間的數據類型是否可以匹配等;同時會進行常量摺疊(int a = 1+2 摺疊爲 int a =3);Flow
:語義分析過程,數據及控制流分析。這一步是對程序上下文邏輯更進一步的驗證,能夠檢查出諸如程序局部變量在使用前是否有賦值、方法的每條路徑是否都有返回值、是否全部的受檢驗異常都被正確處理了等問題。final類型的局部變量就是經過在這一步分析來保證不被從新賦值的;由於局部變量不像類變量,在Class文件中有CONSTANT_Fieldref_info符號引用,記錄了訪問標誌。
Desugar
:解除語法糖(inner classes, class literals, assertions, foreach loops),重寫AST;Generate
:生成字節碼,同時會進行少許代碼添加和轉換工做。如:添加實例構造器
<init>()
方法和類構造器<clinit>()
方法;把字符串相加操做替換爲StringBuffer或者StringBuilder(JDK 1.5+);
四、註解處理器
處理註解
流程,這個流程是經過提供一組
插入式註解處理器
的標準API(Java規範提案 JSR 269: Pluggable Annotation Processing API )在編譯期間對註解進行處理。咱們能夠把它看作是一組
編譯器的插件
,在插件中能夠讀取,修改和添加抽象語法樹中的任意元素。
JSR269是從Java6開始提供; 在Java5 以前註解處理器還沒有成熟,註解處理器的API並非JDK標準,而是經過獨立的apt工具(Annotation Processor Tool,分發於 com.sun.mirror
包下)來編寫自定義處理器。
插入式註解處理器
在處理註解期間修改了AST(抽象語法樹),編譯器將回到解析與填充符號表的過程從新處理,直到全部插入式註解處理器都沒有在修改AST爲止,每一次循環成爲一個
Round
,以下圖:
4.一、註解處理器與反射的區別
編譯期
利用註解進行檢查和改寫語法樹的能力,與反射的
運行期
干預不一樣,大大提升了執行效率。
4.二、如何實現一個註解處理器
javax.annotation.processing.Processor
接口,遵循給定的協定。
爲了方便實現,同時提供了
javax.annotation.processing.AbstractProcessor
類實現具備自定義處理器通用功能的抽象實現。
如下是該接口的關鍵須要實現的方法,註釋處理期間,Java編譯器將調用這兩個方法:
|
|
javax.annotation.processing.SupportedAnnotationTypes
:用於註冊處理器支持的註解。有效值是註釋類型的標準名稱,容許使用通配符。javax.annotation.processing.SupportedSourceVersion
:用於註冊處理器支持的源代碼版本。javax.annotation.processing.SupportedOptions
:此註釋用於註冊容許經過命令行傳遞的自定義選項。
http://scg.unibe.ch/archive/projects/Erni08b.pdf
|
|
|
|
4.2.一、寫一個註解
|
|
4.2.二、寫一個註解處理器
|
|
4.2.三、經過SPI註冊你的註解處理器
javax.annotation.processing.Processor
文件中填寫註解處理器,一行一個,本例子中該文件的內容爲:
|
|
4.2.四、打包而且使用你的lib包
|
|
重點!
的地方,不能配錯了,不然可能致使打包失敗。
4.2.五、使用案例
|
|
|
|
javap -v
查看對應的反彙編代碼:
@ForceAssertions
,咱們把它加到類上面,從新編譯,發現assert已經被替換掉了:
該例子完整代碼: https://github.com/arthinking/pluggable-annotation-processor
4.三、註解處理器其餘相關應用
4.3.一、Lombok
Lombok
,能夠消除POJO中冗長的get, set, hashCode, equals, 構造參數等代碼,這也是經過註解處理器來實現的。
Lombok
基於JSR 269,而且hack了javac和jdt以便可以訪問和修改類的抽象語法樹的內部實現。
@Builder
功能更,能夠參考此文:
https://www.cnblogs.com/throwable/p/9139908.html
4.3.二、Dagger
Dagger
是一種快速,輕量級的依賴注入框架,該框架可用於Java和Android,該框架在編譯時注入以得到更高的行能。
Dagger是第一個實現標準
javax.inject
註解的DI框架(JSR 330)。
其底層也是經過註解處理器實現的,其核心處理類是
ComponentProcessor
,繼承了Google Auto提供的抽象註解處理框架的
BasicAnnotationProcessor
實現的。
依賴注入
是
控制反轉
原理的具體應用,不一樣的框架以不一樣的方式實現依賴注入,這裏咱們對比如下兩類:
運行時
依賴注入
,一般基於反射,更易於使用,可是會致使運行時更慢,Spring就是運行時的DI框架;編譯時生成具體的代碼,這意味着全部繁重的操做都是在編譯期間執行的,編譯時DI增長了複雜性,可是一般執行的更快,Dagger就是編譯時
依賴注入
。
4.3.三、Checker
@NonNull
註解代表ref必須引用到非空的對象:
|
|
|
|
|
|
References
https://www.edureka.co/blog/just-in-time-compiler/
https://www.cnblogs.com/blogtech/p/10000162.html
https://www.cnblogs.com/LittleHann/p/4754446.html
http://scg.unibe.ch/archive/projects/Erni08b.pdf
https://www.jianshu.com/p/63038c7c515a
https://www.cnblogs.com/throwable/p/9139908.html
https://www.jcp.org/en/jsr/detail?id=269
https://www.slideshare.net/ltearno/gwt-and-jsr-269s-pluggable-annotation-processing-api
https://deors.wordpress.com/2011/10/08/annotation-processors/
https://www.baeldung.com/dagger-2
https://objectcomputing.com/resources/publications/sett/java-annotation-dependency-injection-beyond
·END·
點擊「閱讀原文」查看個人博客更多文章
本文分享自微信公衆號 - Java架構雜談(itread)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。