想自己寫框架?不會寫Java註解可不行

愛笑的架構師發表於2020-10-26

圖片

用註解一時爽,一直用一直爽

Java後端開發進入spring全家桶時代後,開發一個微服務提供簡單的增刪改查介面跟玩泥巴似的非常簡單,一頓操作猛如虎,回頭一看程式碼加了一堆註解:@Controller @Autowired @Value,面向註解程式設計變成了大家不可缺少的操作。

想象一下如果沒有註解Java程式設計師可以要哭瞎?

既然註解(annotation)這麼重要,用的這麼爽,那註解的實現原理你知道麼?我猜你只會用註解不會自己寫註解(手動滑稽)。

好了,下面的內容帶大家從零開始寫一個註解,揭開註解神祕的面紗。

 

原來註解不神祕

註解用大白話來說就是一個標記或者說是特殊的註釋,如果沒有解析這些標記的操作那它啥也不是。

註解的格式如同類或者方法一樣有自己特殊的語法,這個語法下文會詳細介紹。

那如何去解析註解呢?這就要用到Java強大的反射功能了。反射大家應該都用過,可以通過類物件獲取到這個類的各種資訊比如成員變數、方法等,那註解標記能不能通過反射獲取呢?當然可以了。

所以註解的原理其實很簡單,本質上是通過反射功能動態獲取註解標記,然後按照不同的註解執行不同的操作,比如@Autowired可以注入一個物件給變數賦值。

看到這裡是不是很躁動啊,來吧自己也擼一個註解。

 

造火箭啦,自己動手寫一個註解

便於大家理解,這裡先引入一個場景:線上教育火了,經理讓我寫一個模組實現學生資訊管理功能,考慮到分散式併發問題,經理讓我務必加上分散式鎖。

經理問我幾天能搞定?我說至少3天。如是腦補了以下程式碼:

圖片

 

經理走後我在思考,我能不能只花一天時間寫完,剩下兩天時間用來寫部落格划水呢?突然靈感來了,我可以把重複的程式碼邏輯抽出來用註解實現不就節省程式碼了,哈哈,趕緊寫。

使用註解之後整個方法清爽了很多,HR小姐姐都誇我寫的好呢。

圖片

 

程式碼已經寫完上庫了,現在我在划水寫部落格呢。是不是很簡潔很優雅很牛逼,怎麼做到的呢,主要分為三步:1開啟冰箱門,2把大象放進去,3把冰箱門關好。好了,扯遠了,大家接著往下看。

 

第一步定義一個註解

圖片

 

一個註解可以簡單拆解為三個部分:

第一部分:註解體

註解的定義有點類似於介面(interface),只不過前面一個加了一個@符號,這個千萬不能省。

第二部分:註解變數

註解變數的語法有點類似於介面裡面定義的方法,變數名後面帶一對括號,不同的是註解變數後面可以有預設值。另外返回值只能是Java基本型別、String型別或者列舉類,不可以是物件型別。

第三部分:元註解

元註解(meta-annotation)說白了就是給註解加註解的註解,是不是有點暈了,這種註解是JDK提前內建好的,可以直接拿來用的。不太懂也沒有關係反正數量也不多,總共就4個,我們背下來吧:@Target @Retention @Documented @Inherited

  • Target註解

用來描述註解的使用範圍,即被修飾的註解可以用在什麼地方 。

註解可以用於修飾 packages、types(類、介面、列舉、註解類)、類成員(方法、構造方法、成員變數、列舉值)、方法引數和本地變數(如迴圈變數、catch引數),在定義註解類時使用了@Target 能夠更加清晰的知道它能夠被用來修飾哪些物件,具體的取值範圍定義在ElementType.java 列舉類中。

比如上面我們寫的Redis鎖的註解就只能用於方法上了。

  • Retention註解

用來描述註解保留的時間範圍,即註解的生命週期。在 RetentionPolicy 列舉類中定義了三個週期:

public enum RetentionPolicy {
    SOURCE, // 原始檔保留
    CLASS,  // 編譯期保留,預設值
    RUNTIME // 執行期保留,可通過反射去獲取註解資訊
}

像我們熟知的@Override註解就只能保留在原始檔中,程式碼編譯後註解就消失了。 比如上面我們寫的Redis鎖的註解就保留到了執行期,執行的時候可以通過反射獲取資訊。

  • Documented註解

用來描述在使用 javadoc 工具為類生成幫助文件時是否要保留其註解資訊,很簡單不多解釋了。

  • Inherited註解

被Inherited註解修飾的註解具有繼承性,如果父類使用了被@Inherited修飾的註解,則其子類將自動繼承該註解。

好了,這一步我們已經將註解定義好了,但是這個註解如何工作呢?接著看。

 

第二步實現註解的業務邏輯

在第一步中我們發現定義的註解(@EnableRedisLock)中沒有業務邏輯,只有一些變數,別忘了我們的註解是要使能Redis分散式鎖的功能,那這個註解到底是怎麼實現加鎖和釋放鎖的功能呢?這個就需要我們藉助反射的強大功能了。

圖片

 

這裡藉助了切面的功能,將EnableRedisLock註解作為一個切點,只要方法上標註了這個註解就會自動執行這裡的程式碼邏輯。

通過反射機制拿到註解物件後就可以執行加鎖解鎖的常用邏輯啦。Redis實現分散式鎖相信大家已經很熟悉了,這裡就不在囉嗦了。

 

第三步在業務程式碼中盡情的使用註解

@EnableRedisLock(lockKey = "student", expireTime = 10, timeUnit = TimeUnit.SECONDS, retryTimes = 5)
public void method1(Student student) {
    // 這裡寫業務邏輯
}

在需要加鎖的方法上直接加上註解就可以啦,怎麼樣是不是很簡單呀,趕緊在你的專案中運用起來吧。 好了,自己寫一個註解的內容就介紹到這裡了,學會了嗎?

相關文章