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

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d0/d0a2a47c6d1a9d3df79c270273fb6db0.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"用註解一時爽,一直用一直爽"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java後端開發進入spring全家桶時代後,開發一個微服務提供簡單的增刪改查接口跟玩泥巴似的非常簡單,一頓操作猛如虎,回頭一看代碼加了一堆註解:@Controller @Autowired @Value,面向註解編程變成了大家不可缺少的操作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"想象一下如果沒有註解Java程序員可以要哭瞎:sob:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"既然註解(annotation)這麼重要,用的這麼爽,那註解的實現原理你知道麼?我猜你只會用註解不會自己寫註解(手動滑稽)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"好了,下面的內容帶大家從零開始寫一個註解,揭開註解神祕的面紗。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"原來註解不神祕"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"註解用大白話來說就是一個標記或者說是特殊的註釋,如果沒有解析這些標記的操作那它啥也不是。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"註解的格式如同類或者方法一樣有自己特殊的語法,這個語法下文會詳細介紹。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那如何去解析註解呢?這就要用到Java強大的反射功能了。反射大家應該都用過,可以通過類對象獲取到這個類的各種信息比如成員變量、方法等,那註解標記能不能通過反射獲取呢?當然可以了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以註解的原理其實很簡單,本質上是通過反射功能動態獲取註解標記,然後按照不同的註解執行不同的操作,比如@Autowired可以注入一個對象給變量賦值。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看到這裏是不是很躁動啊,來吧自己也擼一個註解。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"造火箭啦,自己動手寫一個註解"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"便於大家理解,這裏先引入一個場景:在線教育火了,經理讓我寫一個模塊實現學生信息管理功能,考慮到分佈式併發問題,經理讓我務必加上分佈式鎖。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"經理問我幾天能搞定?我說至少3天。如是腦補了以下代碼:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/02/025609a5e1186b19c97d203d7096c055.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"未使用註解前"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"經理走後我在思考,我能不能只花一天時間寫完,剩下兩天時間用來寫博客划水呢?突然靈感來了,我可以把重複的代碼邏輯抽出來用註解實現不就節省代碼了,哈哈,趕緊寫。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用註解之後整個方法清爽了很多,HR小姐姐都誇我寫的好呢。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/68/6813e9fa65582d0bf937db7c9e72e4f6.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用註解後"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼已經寫完上庫了,現在我在划水寫博客呢。是不是很簡潔很優雅很牛逼,怎麼做到的呢,主要分爲三步: 1打開冰箱門,2把大象放進去,3把冰箱門關好 。好了,扯遠了,大家接着往下看。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"第一步定義一個註解"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ce/cea249f4c2841d90665b873332a62c0f.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"註解的三大組成部分"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個註解可以簡單拆解爲三個部分:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一部分:註解體"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"註解的定義有點類似於接口(interface),只不過前面一個加了一個@符號,這個千萬不能省。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第二部分:註解變量"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"註解變量的語法有點類似於接口裏面定義的方法,變量名後面帶一對括號,不同的是註解變量後面可以有默認值。另外返回值只能是Java基本類型、String類型或者枚舉類,不可以是對象類型。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第三部分:元註解"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"元註解(meta-annotation)說白了就是給註解加註解的註解,是不是有點暈了,這種註解是JDK提前內置好的,可以直接拿來用的。不太懂也沒有關係反正數量也不多,總共就4個,我們背下來吧:@Target @Retention @Documented @Inherited"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Target註解"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用來描述註解的使用範圍,即被修飾的註解可以用在什麼地方 。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"註解可以用於修飾 packages、types(類、接口、枚舉、註解類)、類成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數),在定義註解類時使用了@Target 能夠更加清晰的知道它能夠被用來修飾哪些對象,具體的取值範圍定義在ElementType.java 枚舉類中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如上面我們寫的Redis鎖的註解就只能用於方法上了。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Retention註解"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用來描述註解保留的時間範圍,即註解的生命週期。在 RetentionPolicy 枚舉類中定義了三個週期:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"public enum RetentionPolicy {\n SOURCE, // 源文件保留\n CLASS, // 編譯期保留,默認值\n RUNTIME // 運行期保留,可通過反射去獲取註解信息\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"像我們熟知的@Override註解就只能保留在源文件中,代碼編譯後註解就消失了。比如上面我們寫的Redis鎖的註解就保留到了運行期,運行的時候可以通過反射獲取信息。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Documented註解"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用來描述在使用 javadoc 工具爲類生成幫助文檔時是否要保留其註解信息,很簡單不多解釋了。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Inherited註解"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"被Inherited註解修飾的註解具有繼承性,如果父類使用了被@Inherited修飾的註解,則其子類將自動繼承該註解。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"好了,這一步我們已經將註解定義好了,但是這個註解如何工作呢?接着看。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"第二步實現註解的業務邏輯"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在第一步中我們發現定義的註解(@EnableRedisLock)中沒有業務邏輯,只有一些變量,別忘了我們的註解是要使能Redis分佈式鎖的功能,那這個註解到底是怎麼實現加鎖和釋放鎖的功能呢?這個就需要我們藉助反射的強大功能了。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/89/89b9e3b4e03df12ea551b5ee2f743e70.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 註解的操作"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏藉助了切面的功能,將EnableRedisLock註解作爲一個切點,只要方法上標註了這個註解就會自動執行這裏的代碼邏輯。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過反射機制拿到註解對象後就可以執行加鎖解鎖的常用邏輯啦。Redis實現分佈式鎖相信大家已經很熟悉了,這裏就不在囉嗦了。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"第三步在業務代碼中盡情的使用註解"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"@EnableRedisLock(lockKey = \"student\", expireTime = 10, timeUnit = TimeUnit.SECONDS, retryTimes = 5)\npublic void method1(Student student) {\n // 這裏寫業務邏輯\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在需要加鎖的方法上直接加上註解就可以啦,怎麼樣是不是很簡單呀,趕緊在你的項目中運用起來吧。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"好了,自己寫一個註解的內容就介紹到這裏了,學會了嗎?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"- END -"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"看完三件事❤️"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:"}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"點贊,轉發,有你們的 『點贊和評論』,纔是我創造的動力。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"關注公衆號 『 Java鬥帝 』,不定期分享原創知識。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"同時公衆號內回覆“666”即可免費領取1000道互聯網面試題"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章