用注解一時爽,一直用一直爽
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){
//?這里寫業務邏輯
}
在需要加鎖的方法上直接加上注解就可以啦,怎么樣是不是很簡單呀,趕緊在你的項目中運用起來吧。
好了,自己寫一個注解的內容就介紹到這里了,學會了嗎?