你該學會自己寫 Java 注解了
?我們通過Hello World這個例子引入了RPC 框架,知道了客戶端要想調用服務端需要靠兩個注解來實現,下面我們一起來實現這兩個注解。
注解相關的實現代碼是 RPC 框架的核心代碼,后面寫完后可以打包成一個 jar 包作為框架供業務代碼中使用,這樣我們前面寫的客戶端和服務端 demo 就可以正常工作了。
好了,鋪墊這么多,我們真正開始寫 RPC 框架代碼了。RPC 框架計劃提供兩個注解:
- @ServiceReference
- @ServiceExpose
@ServiceReference
@ServiceReference?注解用來引用服務端提供的服務,客戶端啟動后可以自動注入對應的bean,像調用本地方法一樣調用遠程服務的方法。
首先,我們來定義一個注解類,interface?關鍵字用來聲明接口,前面加一個@?就可以用來定義注解類,如上面約定客戶端側注解名為:ServiceReference。
注解類還可以加很多配置項,一般用幾個元注解進行修飾:
@Target?表示我們定義的這個注解使用的范圍,ElementType?是枚舉類有很多枚舉值,這里我們只用到ElementType.FIELD,業務含義:當前這個自定義注解只能在類的成員變量上使用。
@Retention?表示注解的保留策略,RetentionPolicy.RUNTIME?的意思是希望注解能一直保留到運行期,那為什么要保留到運行期呢?因為我們希望在運行期通過這個注解自動注入依賴。如果取值為RetentionPolicy.SOURCE則表示僅保存在源碼中,在代碼編譯后就會丟掉這個注解的信息。
@Documented與文檔相關的,沒有其他業務含義,這里不再贅述。
一個完整的注解類詳細代碼如下:
注解已經定義好了,代碼非常簡單,使用起來也比較簡單,在類的成員變量上加一個這樣的注解即可:
可能有小伙伴要問了,為什么加一個簡單的注解就能將遠程服務的依賴注入進來?這其實是框架背后的功勞,服務啟動后會自動掃描框架的注解,根據不同的注解框架會有對應的初始化動作,至于@ServiceReference的初始化邏輯我們下一個小節再詳細展開講。
下面接著看另外一個注解。
@ServiceExpose
@ServiceExpose注解用于服務端暴露自己的服務接口(方法),進而可被客戶端發現調用。
與@ServiceReference?類似,定義一個注解,取名叫做:ServiceExpose。
與@ServiceReference?稍微有點不同的是,多增加了一個元注解:@Component?以及@Target取值不一樣。
@Component是Spring?原生的注解,Spring?啟動后會掃描注解并將其初始化一個bean?,用于配合@ServiceExpose注解使用,具體邏輯后面章節會詳細介紹。
@Target?用于約束注解的使用范圍,ElementType.TYPE表示當前這個注解僅可在類(class)、接口(interface)、枚舉(enum)類上使用,在其他地方使用是非法的,會編譯失敗。
完整的代碼如下:
代碼結構
在前面搭建環境時創建了一個maven?工程,我們繼續在工程中創建一個 package并取名為:annotation,剛才寫完的兩個注解類代碼放進去。
目前框架的代碼結構如下:
小結
前面帶領大家寫完了框架中核心的兩個注解類:@ServiceReference? 和 @ServiceExpose?,客戶端常使用@ServiceReference?引用服務端;服務端常使用@ServiceExpose暴露自身的服務便于客戶端發現和使用。
定義注解的步驟非常簡單:
- 使用@interface聲明注解類
- 注解類前面添加元注解,如:@Target、@Retention等
相信大家也發現了,注解類定義好之后并不能立馬生效,比如在一個類上添加注解@ServiceReference,我們期望服務啟動后這個類能自動暴露自己,但是你會發現什么也沒發生,這是為什么呢?
其實注解僅僅只是一種標記的手段,自身并無業務邏輯,如果你希望注解實現預期效果,需要自己去寫一段驅動代碼,代碼中可以通過反射方式掃描所有添加了注解的地方,然后執行對應的邏輯,至于什么時候執行這段驅動代碼,需要結合注解的保留策略,一般是編譯或者運行中執行。
明白了這個道理之后,要想使@ServiceReference? 和 @ServiceExpose這兩個注解實現對應的功能,需要分別寫一段驅動程序,這段代碼在后續的章節會詳細介紹,我們接著往下看。