學習筆記3:AbstractProcessor-編譯時注解處理器
因為寫代碼想偷懶,最近一直在做夢可以用注解簡化一些重復性比較高的代碼,所以學習了半天Java的注解處理器怎么用。雖然學完以后我的感嘆是為了偷懶而花費了幾倍的時間學習了一份我現在應該完全用不到的知識,感到非常憂郁(捂臉)
本著來都來了的精神,還是大體總結下我學了啥知識。畢竟真的不記錄就是純時間浪費了(捂臉)現在網絡上的信息實在是太混亂了,很多東西一查全都是復制粘貼,經常一頁都是內容完全一樣的東西,一眼爬蟲自動生成,實在優(yōu)點沒轍,這次查的不記下來,下次真的又找不到了.......
?
1.注解處理器Processor
Java在定義注解時,可以將注解定義為3個等級:
RentationPolicy.SOURCE:只保留到源代碼,編譯成.class文件時就丟棄
RentationPolicy.CLASS:編譯后保留到.class文件里,但是運行時不加載。
RentationPolicy.RUNTIME:運行時會加載
?
暫時不是很清楚RentationPolicy.CLASS有什么用,可能我還要學習。
RentationPolicy.SOURCE就是主要用于注解處理器的部分了。
Java在編譯代碼之前,會通過注解處理器分析代碼,并提供持有特定接口的對象集合供注解處理器分析處理,這個時候注解處理器可以基于注解提供的信息生成額外的java文件加入到編譯流程里。最終生成的class文件內就會包含額外生成的代碼部分。
在編譯前對代碼進行處理使用的基礎類型為接口Processor,一般可以使用實現了大部分功能的類型AbstractProcessor作為代替。
?
因為還沒有探索好AbstractProcessor在什么實際場景應用比較合適,所以這里簡單記錄一下我建立兩個測試項目,并且實現注解處理器自動生成代碼,以及對注解處理器進行調試的流程
?
2.建立主項目
?
主項目主要只需要建立一個測試注解,以及一個使用了該注解的測試類
成員方法和構造函數都是隨便亂寫的,主要是為了測試自動生成代碼能否進行
理想情況下,注解處理器應當可以自動發(fā)現持有TestAnnotation的類BasicClass,并且生成相關代碼
3.建立注解處理器項目
注解處理器不能與主項目放到一起,必須獨立建立一個項目,并且按照指定方式生成一個jar包放置到主項目的lib目錄下。如果注解處理器想要引用主項目的部分定義(例如接口定義等反射信息)需要怎么弄,我這里也搞不清楚,目前是按照寫死的方式進行的處理。
(比較重要的部分都寫注釋里了懶得額外寫說明了())
4.修改注解處理器項目的生成方式,并且獲得jar包,在主項目中運行
注解處理器制作出來不等于可以立刻使用,需要生成到jar包再導入到主項目。
以idea為例,需要在Project Structure -> Artifacts里添加一個JAR的目標,在jar根目錄下創(chuàng)建文件夾 ~/META-INF/services/ ,并添加文件名為“javax.annotation.processing.Processor”的文件,文件內容為當前jar包所有注解處理器的全包名,例如本項目的該文件內容如下:
(當然,通過引入谷歌提供的@AutoService注解,可以不需要自己聲明jar包里的這個文件)
?
在配置好之后,對項目實行build Artifact操作,從~/out/artifacts目錄下找到jar包,復制到主項目的lib文件夾下,添加libraries。并且修改Settings -> Build, Execution, Deployment -> Complier -> Annotation Processors,將Enable annotation processing勾選,之后進行build時就會將生成的代碼輸出了。?

5.對注解處理器進行的調試(以idea為例)
?
Processor相關的操作在編譯前進行,實際上是另開了一個JVM進行編譯操作,因此正常方式下無法對其進行斷點等方式測試,只能輸出日志。在網上稍微查了下,學習了一下在不利用Spring或者gradle,只使用idea進行注解處理器的調試的方法,步驟如下:
?
1) “Edit Custom VM Options”,添加以下聲明(端口可以自定義,后面需要使用相同端口),修改了這個設置之后需要重啟idea
-Dcompiler.process.debug.port=8000
2)"Debug Build Process",將其調節(jié)為on(每次打開idea都會自動變成off,需要重新打開),之后build主項目,現在主項目就會監(jiān)聽8000端口并等待調試器接入
3)打開注解處理器項目,添加一個remote調試項目,設置好端口以后,設置斷點并啟動,就可以開始遠程調試注解處理器了。
注意:用完以后一定要將Debug Build Process關閉,否則后面idea啟動其他編譯都會卡住

6.我對AbstractProcessor的評價:
abstractProcessor可以在java編譯class文件之前介入,批量生成代碼或者資源文件,generate的代碼也可以直接在主項目里引用,相對于我們自己的項目里經常必須啟動一個ant跑一次來產生代碼,注解處理器提前生成代碼可以減少一部分操作復雜度。
但是其作用范圍感覺還是有一些有限,這些有限性在于:
1.build的過程中并沒有啟動主項目,所以無法直接應用代碼里的反射信息,可以間接利用的反射信息有限。使用編譯時注解處理器的時候一般需要通過整個文件對必要的class,field和method都寫好注解的方式來指引如何生成指定的java文件。
2.不能修改已有文件,只能生成新的java文件,因此無法對已有代碼產生直接影響。
?
因為游戲服務器對于性能要求經常比較高,運行時注解等反射的方式一般不適合在游戲服務器主流程上運行,而注解處理器也不能修改現有代碼。如果想要按照一定的規(guī)則,批量性修改已有代碼,就需要另外尋找其他方式。之后我學習了JavaParser,就能實現相關功能。這是下次準備記錄的內容。