問題背景git
好久好久前,在我仍是青銅的時候(如今依舊是青銅段位)去面試,面試官問我怎麼獲取類,方法上的註解。程序員
當時的我也算用過註解,順口就回答了,用 isAnnotationPresent 判斷是否加了註解, getAnnotation 獲取註解對象,而後獲取註解中的值。github
大體的代碼是這樣子的:面試
正在我沾沾自喜的時候,面試官又乘勝追擊了,那麼在讀取註解的時候,有沒有什麼狀況會致使剛剛你說的方式是不能成功判斷和讀取的呢?sql
這我一下蒙圈了,還會有讀取不到的狀況麼?以前沒遇到過啊,因而我斬釘截鐵的回答面試官,不可能讀取不到的,面試官笑了笑............api
在個人加密框架monkey-api-encrypt(https://github.com/yinjihuan/monkey-api-encrypt)中,支持了註解標識加解密的功能,實際上是經過讀取註解,轉換成uri的操做。緩存
一開始也是用的上面的方式進行註解的讀取操做,當咱們程序中的Controller被AOP切入後,註解讀取不到了,這就是今天要分享的問題。架構
正常狀況下,咱們的class是 com.cxytiandi.eureka_client.controller.ArticleController 這種形式,若是用了AOP後,那麼就會變成 com.cxytiandi.eureka_client.controller.ArticleController$$EnhancerBySpringCGLIB$$3323dd1e這樣了。併發
解決方案一框架
這種狀況下拿到的Method也是被代理了的,因此Method上的註解天然獲取不到,既然知道緣由了,最簡單快速的解決方法就是將多餘的內容截取掉,而後從新獲得一個沒有被代理的Class對象,經過這個Class對象來獲取Method,這樣就能夠獲取到Method上的註解。
解決方案二
雖然問題解決了,可是仍是以爲不夠優雅,有沒有更好的方式呢?咱們能夠用Spring裏面提供的AnnotationUtils來讀取註解。
AnnotationUtils.findAnnotation()原理是什麼呢?爲何它能夠獲取到被代理後方法上的註解呢?
要想知道原理,那就只能看源碼啦,源碼多,不貼出來了,貼一點點關鍵的就好了
首先會構建一個AnnotationCacheKey,從本地緩存中獲取,若是有的話直接返回,也就意味着只要讀取過就會被緩存起來:
而後就是判斷是否橋接方法,若是不是就直接返回,是的話則獲取橋接方法的註解,若是還獲取不到就經過接口來獲取。
後面就不繼續下去了,最關鍵的代碼實際上是這句:
由於CGLIB代理會爲目標類動態生成一個子類,因此咱們要獲取最原始的類,直接使用getSuperclass就能夠了,跟第一種方案是一致的,只是第一種看起來有點那啥哈.....
推薦你們用AnnotationUtils去獲取,這裏面封裝了不少的邏輯,考慮了不少場景下的問題,切莫重複造輪子。
歡迎工做一到五年的Java工程師朋友們加入Java程序員開發: 721575865
羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!