注解處理器(Annotation Processor)原理簡(jiǎn)析

如果不知道注解處理器(Annotation Processor),可以先查看一下我上一篇寫的注解處理器(Annotation Processor)簡(jiǎn)析,先了解下Annotation Processor的用法,再來(lái)看下原理.

首先,我們知道,自定義的Annotation Processor都要繼承于類AbstractProcessor,那么,我們來(lái)簡(jiǎn)略看下AbstractProcessor的文檔介紹:


AbstractorProcessor

可以看到,AbstractProcessor實(shí)現(xiàn)了接口Processor,那么,我們?cè)趤?lái)看下Processor的api文檔:

javax.annotation.processing
Interface Processor

All Known Implementing Classes:
AbstractProcessor


public interface Processor

The interface for an annotation processor.

Annotation processing happens in a sequence of rounds. On each round, a processor may be asked to process a subset of the annotations found on the source and class files produced by a prior round. The inputs to the first round of processing are the initial inputs to a run of the tool; these initial inputs can be regarded as the output of a virtual zeroth round of processing. If a processor was asked to process on a given round, it will be asked to process on subsequent rounds, including the last round, even if there are no annotations for it to process. The tool infrastructure may also ask a processor to process files generated implicitly by the tool's operation.
Each implementation of a Processor must provide a public no-argument constructor to be used by tools to instantiate the processor. The tool infrastructure will interact with classes implementing this interface as follows:

  1. If an existing Processor object is not being used, to create an instance of a processor the tool calls the no-arg constructor of the processor class.
  2. Next, the tool calls the init
    method with an appropriate ProcessingEnvironment .
  3. Afterwards, the tool calls getSupportedAnnotationTypes
    , getSupportedOptions
    , and getSupportedSourceVersion
    . These methods are only called once per run, not on each round.
  4. As appropriate, the tool calls the process
    method on the Processor object; a new Processor object is not created for each round.

If a processor object is created and used without the above protocol being followed, then the processor's behavior is not defined by this interface specification.The tool uses a discovery process to find annotation processors and decide whether or not they should be run. By configuring the tool, the set of potential processors can be controlled. For example, for a JavaCompiler
the list of candidate processors to run can be set directly or controlled by a search path used for a service-style lookup. Other tool implementations may have different configuration mechanisms, such as command line options; for details, refer to the particular tool's documentation. Which processors the tool asks to run is a function of what annotations are present on the root elements, what annotation types a processor processes, and whether or not a processor claims the annotations it processes. A processor will be asked to process a subset of the annotation types it supports, possibly an empty set. For a given round, the tool computes the set of annotation types on the root elements. If there is at least one annotation type present, as processors claim annotation types, they are removed from the set of unmatched annotations. When the set is empty or no more processors are available, the round has run to completion. If there are no annotation types present, annotation processing still occurs but only universal processors which support processing "*"
can claim the (empty) set of annotation types.
Note that if a processor supports "*"
and returns true
, all annotations are claimed. Therefore, a universal processor being used to, for example, implement additional validity checks should return false
so as to not prevent other such checkers from being able to run.
If a processor throws an uncaught exception, the tool may cease other active annotation processors. If a processor raises an error, the current round will run to completion and the subsequent round will indicate an error was raised. Since annotation processors are run in a cooperative environment, a processor should throw an uncaught exception only in situations where no error recovery or reporting is feasible.
The tool environment is not required to support annotation processors that access environmental resources, either per round or cross-round, in a multi-threaded fashion.
If the methods that return configuration information about the annotation processor return null
, return other invalid input, or throw an exception, the tool infrastructure must treat this as an error condition.
To be robust when running in different tool implementations, an annotation processor should have the following properties:

  1. The result of processing a given input is not a function of the presence or absence of other inputs (orthogonality).
  2. Processing the same input produces the same output (consistency).
  3. Processing input A followed by processing input B is equivalent to processing B then A(commutativity)
  4. Processing an input does not rely on the presence of the output of other annotation processors (independence)

The Filer
interface discusses restrictions on how processors can operate on files.
Note that implementors of this interface may find it convenient to extend AbstractProcessor
rather than implementing this interface directly.

Since:
1.6

注解處理發(fā)生在一系列回合中.每個(gè)回合中,注解處理器都有可能被叫去處理由上一次注解產(chǎn)生的源碼和類文件中的找到的注解子集.第一次注解處理回合的輸入就是工具第一次運(yùn)行的輸入;這些初始輸入可以認(rèn)為是一個(gè)虛擬的第零次注解處理回合的輸出.如果注解處理器被叫去處理一個(gè)特定的回合,那么接下來(lái)的回合它都會(huì)繼續(xù)處理,即使后續(xù)回合沒(méi)有它需要處理的注解.注解處理器有可能會(huì)被叫去處理由(編譯)工具隱式生成的文件.每個(gè)注解處理器的實(shí)現(xiàn)都必須提供一個(gè)公有的無(wú)參構(gòu)造函數(shù),由工具進(jìn)行實(shí)例化.工具會(huì)與實(shí)現(xiàn)該接口(Processor)的類進(jìn)行如下交互:

  1. 如果一個(gè)已存在的Processor實(shí)例未被使用,(編譯)工具會(huì)調(diào)用注解處理器的無(wú)參構(gòu)造函數(shù)實(shí)例化出一個(gè)Processor對(duì)象.
  2. 接下來(lái),(編譯)工具會(huì)調(diào)用init函數(shù),并傳入一個(gè)合適的ProcessingEnvironment.
  3. 之后,(編譯)工具會(huì)調(diào)用getSupportedAnnotationTypes,getSupportedOptions和getSupportedSourceVersion.這些方法只會(huì)在每一次運(yùn)行時(shí)被調(diào)用一次,而不會(huì)在每個(gè)注解回合都被調(diào)用.
  4. 正常情況下,(編譯)工具會(huì)調(diào)用注解處理器實(shí)例的process函數(shù);每個(gè)注解回合并不會(huì)產(chǎn)生新的注解實(shí)例.

如果一個(gè)注解處理器實(shí)例被創(chuàng)建,但是使用卻沒(méi)有遵循上述協(xié)議,那么這個(gè)注解處理器的行為并未被該接口規(guī)范定義.(編譯)工具使用搜索程序去找到注解處理器并決定它們是否得以運(yùn)行.通過(guò)配置(編譯)工具,潛在的注解處理器可以被控制.比如,對(duì)于javaCompiler,候選處理器可以直接被指定或者通過(guò)使用service-style查找指定搜索路徑進(jìn)行控制.其他(編譯)工具可以具有不同的配置機(jī)制,比如控制行選項(xiàng);具體點(diǎn)講,參考特定工具文檔.(編譯)工具會(huì)調(diào)用運(yùn)行的注解處理器是由root elements指示的注解,是注解處理器處理的注解類型和注解處理器聲明它要處理的注解的方法.注解處理器會(huì)被叫去處理它支持的注解類型子集,有可能是一個(gè)空的集合.在給定回合,(編譯)工具會(huì)計(jì)算root elements的注解類型集合.如果有最少一個(gè)注解類型存在,就是注解處理器聲明的注解類型之一,它們就會(huì)被從未匹配的注解類型集合中移除.當(dāng)(未匹配)注解集合為空或者沒(méi)有其它的注解處理器,那么該注解處理回合就結(jié)束了.如果沒(méi)有聲明注解類型,只有通用處理器(支持處理"*"聲明(空)所有注解類型集合)仍然會(huì)進(jìn)行注解處理.注意如果一個(gè)注解處理器支持"*"并且返回true,則所有的注解類型都被聲明.因此,一個(gè)通用注解處理器如果被用于實(shí)現(xiàn)附加有效檢驗(yàn),那么應(yīng)該返回false,為了不防止這類檢驗(yàn)器得以運(yùn)行.如果一個(gè)注解處理器拋出了一個(gè)未捕獲異常,(編譯)工具可能會(huì)停止其他活動(dòng)的注解處理器.如果一個(gè)注解處理器引起了一個(gè)錯(cuò)誤,當(dāng)前注解回合會(huì)結(jié)束,并且后續(xù)回合會(huì)指明一個(gè)錯(cuò)誤產(chǎn)生了.因?yàn)樽⒔馓幚砥鞫际沁\(yùn)行在共同協(xié)作的環(huán)境中,只有當(dāng)錯(cuò)誤恢復(fù)或報(bào)告提交是無(wú)法執(zhí)行的情況下,注解處理器才允許拋出一個(gè)未捕獲異常.
(編譯)工具環(huán)境不要求要支持注解處理器能以多線程方式在每一回合或交叉回合能訪問(wèn)環(huán)境資源.
如果返回注解處理器的配置信息的方法返回null,返回其他無(wú)效輸入,或者拋出一個(gè)異常,(編譯)工具必須將這些當(dāng)做是一個(gè)錯(cuò)誤條件.
為了在不同的工具實(shí)現(xiàn)能夠健壯運(yùn)行,注解處理器必須有以下性能:

  1. 對(duì)于一個(gè)給定的輸入的處理結(jié)果,不影響其他輸入的存在或缺失(正交性)
  2. 處于相同的輸入會(huì)產(chǎn)生相同的輸出(一致性)
  3. 先處理輸入A,然后處于輸入B等同于先處理B在處理A(可交換性)
  4. 處理輸入會(huì)依賴于其他注解處理器的輸出(獨(dú)立性)

Filer接口討論了注解處理器操作文件的限定.
請(qǐng)知悉Processor的實(shí)現(xiàn)通過(guò)繼承AbstractProcessor會(huì)比直接實(shí)現(xiàn)該接口更加方便.

簡(jiǎn)單總結(jié)如下:

  • Annotation Processor可能會(huì)被多次調(diào)用.
  • Annotation Processor被調(diào)用一次后,后續(xù)若還有注解處理,該Annotation Processor仍然會(huì)繼續(xù)被調(diào)用.
  • 自定義Annotation Processor必須帶有一個(gè)無(wú)參構(gòu)造函數(shù),讓javac進(jìn)行實(shí)例化.
  • 如果Annotation Processor拋出一個(gè)未捕獲異常,javac可能會(huì)停止其他的Annotation Processor.只有在無(wú)法拋出錯(cuò)誤或報(bào)告的情況下,才允許拋出異常.
  • Annotation Processor運(yùn)行在一個(gè)獨(dú)立的jvm中,所以可以將它看成是一個(gè)java應(yīng)用程序.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末腔稀,一起剝皮案震驚了整個(gè)濱河市化戳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌套像,老刑警劉巖宵睦,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件靶病,死亡現(xiàn)場(chǎng)離奇詭異滥壕,居然都是意外死亡拌阴,警方通過(guò)查閱死者的電腦和手機(jī)湿刽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門的烁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人诈闺,你說(shuō)我怎么就攤上這事渴庆。” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵襟雷,是天一觀的道長(zhǎng)刃滓。 經(jīng)常有香客問(wèn)我,道長(zhǎng)耸弄,這世上最難降的妖魔是什么咧虎? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮计呈,結(jié)果婚禮上砰诵,老公的妹妹穿的比我還像新娘。我一直安慰自己捌显,他們只是感情好茁彭,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著扶歪,像睡著了一般理肺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上善镰,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天妹萨,我揣著相機(jī)與錄音,去河邊找鬼媳禁。 笑死眠副,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的竣稽。 我是一名探鬼主播囱怕,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼毫别!你這毒婦竟也來(lái)了娃弓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤岛宦,失蹤者是張志新(化名)和其女友劉穎台丛,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砾肺,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡挽霉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了变汪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侠坎。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖裙盾,靈堂內(nèi)的尸體忽然破棺而出实胸,到底是詐尸還是另有隱情他嫡,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布庐完,位于F島的核電站钢属,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏门躯。R本人自食惡果不足惜淆党,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望生音。 院中可真熱鬧宁否,春花似錦、人聲如沸缀遍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)域醇。三九已至台谊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間譬挚,已是汗流浹背锅铅。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留减宣,地道東北人盐须。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像漆腌,于是被迫代替她去往敵國(guó)和親贼邓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容