【如何讓代碼變“高級(jí)”(一)】-Spring組合注解提升代碼維度

開發(fā)中這樣的代碼

對(duì)于每個(gè)開發(fā)人員都會(huì)遇到這樣情況伤靠,代碼如下:

@Api(tags = "自定義組合注解", description = "組合注解優(yōu)化代碼")
@StandardResult
@RequestMapping("/ccww")
@Controller
@ResponseBody
public class CombinationController{

}

在定義某個(gè)類或接口時(shí),使用了Spring自帶的注解(@Controller飘言、@Service峦睡,@Conditional),同時(shí)又要使用公司特定的注解標(biāo)注公司的業(yè)務(wù)嘉抒,接著就出現(xiàn)了以下處理方式的那一幕零聚。

”普通”開發(fā)人員

對(duì)于一般開發(fā)人員來說,只要功能、需求達(dá)到即可隶症,代碼也差不多就可以了,生活也就那樣政模。**只要不出現(xiàn)BUG,測試人員蚂会,產(chǎn)品經(jīng)理不找淋样,萬事大吉了!P沧 趁猴!

生活就像心電圖一樣,一帆風(fēng)順就證明掛了,
因此我們需要一顆折騰的心

image-20191128104802646.png

高級(jí)”開發(fā)員(BUG工程師)

對(duì)于我們這類“高級(jí)”開發(fā)員(BUG工程師)彪见,看到這樣的代碼儡司,一個(gè)類上聲明了五六個(gè)注解,長長的一大串注解余指,代碼看起來就很普通捕犬,體現(xiàn)不出我們“高級(jí)”開發(fā)員(BUG工程師)折騰的心??,BUG創(chuàng)造師的水平酵镜。

而且注解本意是為了提供我們便捷碉碉,代碼優(yōu)化,作標(biāo)注用淮韭。但和XML一樣垢粮,過度使用就編程了一種災(zāi)難。


image-20191128105041607.png

于是我們持著一顆折騰的心??缸濒,尋找一種可以讓自己看來舒服的整潔的代碼修正足丢,現(xiàn)在找到了使用組合注解的方式把需要的注解組合在一個(gè)自定義的組合注解上。

"高級(jí)”開發(fā)人員(BUG工程師)-基于組合注解方案

首先我們持著一個(gè)折騰的心??庇配,想到平時(shí)我們常見的SpringBoot的啟動(dòng)注解@SpringBootApplication斩跌,

為什么它一個(gè)注解可以實(shí)現(xiàn)那么多功能呢?
怎么實(shí)現(xiàn)的呢捞慌?
我們?cè)趺床拍茉趯⑦@個(gè)實(shí)現(xiàn)轉(zhuǎn)化出自己所需的自定義注解呢耀鸦?

接下來我們看看它的源碼:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

    @AliasFor(annotation = EnableAutoConfiguration.class)
    Class<?>[] exclude() default {};
    

    @AliasFor(annotation = EnableAutoConfiguration.class)
    String[] excludeName() default {};
    

    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};
    
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

}

@SpringBootApplication功能列表:

  • 聲明@Inherited注解,聲明了它的類的子類是可以繼承它的

  • 聲明@SpringBootConfiguration注解啸澡,可為類標(biāo)注為配置類

  • 聲明@EnableAutoConfiguration注解袖订,聲明了它的類會(huì)默認(rèn)開啟自動(dòng)配置

  • 聲明@ComponentScan注解,同時(shí)是@ComponentScan注解的容器嗅虏。我們發(fā)現(xiàn)scanBasePackagesscanBasePackageClasses兩個(gè)注解屬性上面同樣聲明了@AliasFor注解洛姑,分別指向了@ComponentScan注解的basePackages注解屬性和basePackageClasses屬性。

  • 聲明了exclude()為排除特定的自動(dòng)配置類以及excludeName()排除特定的自動(dòng)配置類名稱

疑問皮服?楞艾?

  • 這時(shí)我們會(huì)想@SpringBootApplication為什么可以這樣使用呢参咙?

  • 為什么可以繼承?

  • 我們定義的普通類和接口有什么區(qū)別?

  • @AliasFor 為什么可以這樣使用硫眯?

  • ....

其實(shí)蕴侧,基于@Retention的值可以分兩時(shí)期對(duì)注解進(jìn)行處理,:

  1. 編譯時(shí)處理

  2. 運(yùn)行時(shí)處理

@Retention的值為RetentionPolicy.SOURCE時(shí)注解只存在.java源文件中
@Retention的值為RetentionPolicy.CLASS時(shí)注解只存在于.class文件中两入,

都無法在運(yùn)行時(shí)去獲取注解的信息净宵,只能在編譯時(shí)處理

設(shè)定為RetentionPolicy.RUNTIME注解信息會(huì)存在.class文件中

通知單JVM加載.class文件時(shí)會(huì)把注解也加載到JVM中,所以就可在運(yùn)行時(shí)獲取注解的信息

運(yùn)行時(shí)處理:運(yùn)行時(shí)處理是通過反射機(jī)制獲取注解裹纳。

再看看最原始的注解(完全由元注解組成的):

public @Interface Annotation
{

}

創(chuàng)建注解使用@Interface類型聲明為注解择葡,并且聲明為@Interface類型的類在編譯時(shí)會(huì)自動(dòng)繼承Annotation接口。

那什么類型的類可以繼承接口呢剃氧?

自然是接口類型了刁岸,對(duì)編譯器而言,注解其實(shí)就是一個(gè)接口她我。所以,我們?cè)谀硞€(gè)類上聲明注解本質(zhì)上等價(jià)于繼承注解代表的接口迫横。因?yàn)樽⒔獗举|(zhì)上是接口番舆,就具有了相互繼承的能力了。

還有(心想矾踱,這問題少年恨狈,那么多問題),在注解里聲明的注解方法以及給注解屬性賦值怎么處理的呢呛讲?

對(duì)了禾怠,就是JDK動(dòng)態(tài)代理!編譯器把我們的類翻譯為實(shí)現(xiàn)了注解接口的類贝搁,然后用JDK動(dòng)態(tài)代理的方式攔截所有該類方法的調(diào)用吗氏,如果是自定義方法就放行;如果是注解方法就攔截下來執(zhí)行某些邏輯雷逆。至于我們給注解屬性賦值弦讽,會(huì)以JDK動(dòng)態(tài)代理類的常量的方式保存,需要時(shí)使用就可以了膀哲。我們可以看看代理注解的類是怎樣的往产,具體的可以實(shí)現(xiàn)跟蹤源碼看看

最后,@AliasFor的作用是什么呢某宪?

  • 用到注解 屬性上仿村,表示兩個(gè)屬性互相為別名,互相為別名的屬性值必須相同兴喂,若設(shè)置成不同蔼囊,則會(huì)報(bào)錯(cuò)

  • 注解是可以繼承的焚志,但是注解是不能繼承父注解的屬性的,也就是說,我在類掃描的時(shí)候,拿到的注解的屬性值,依然是父注解的屬性值,而不是你定義的注解的屬性值饵隙,所以此時(shí)可以在子注解對(duì)應(yīng)的屬性上加上@AliasFor

手動(dòng)起來齐遵,動(dòng)手優(yōu)化

現(xiàn)在該發(fā)揮我們程序員的核心本領(lǐng)之一“仿寫”,有什么是我們不能仿寫出來的呢腐泻?哈哈( 程序員的傲嬌 )滴肿,話不多說岳悟,擼起袖子,開碼泼差,仿寫@SpringBootApplication注解:

/**
*自定義組合注解
*@author Ccww
*
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
@RequestMapping
@Api
public @interface StandardResultRestControllerApi
{
    /**
    * 定義映射路徑URL
    * @return
    */
   @AliasFor(annotation = RequestMapping.class, value = "path")
   String[] value() default {};

    /**
    *定義spring類名稱
    *@return
    */
    @AliasFor(annotation = Controller.class, value = "value")
    String name() default "";
    /**
    *定義Api類tags屬性
    *@return
    */
    @AliasFor(annotation = Api.class, attribute = "tags")
    String[] tags() default "";
    
    /**
    *定義Api類description屬性
    *@return
    */
    @AliasFor(annotation = Api.class, attribute = "description")
    String description() default "";
}

優(yōu)化后的代碼如下

@StandardResultRestControllerApi(path="/Combination",tags = "自定義組合注解", description = "組合注解優(yōu)化代碼")
public class CombinationController
{
    
}

總結(jié)

經(jīng)過優(yōu)化后贵少,整個(gè)類看起來輕簡了很多。以后碰到類似情況堆缘,可以考慮使用組合注解來進(jìn)行優(yōu)化, 將多個(gè)注解作用于一個(gè)注解滔灶,用一個(gè)注解就可以來實(shí)現(xiàn)那多個(gè)注解的功能,使作用的元素(即方法或類等)看上去更簡潔美觀吼肥,當(dāng)然主要還是更強(qiáng)大的屬性覆蓋功能录平。

但是也要視情況而定,不要盲目的使用組合注解缀皱,不然別人看起這代碼就比較費(fèi)勁了哈6氛狻!(“高級(jí)”程序員的微笑 )

溫馨提示:不要盲目的使用組合注解

優(yōu)點(diǎn):

  • 代碼整齊

缺點(diǎn):

  • 代碼可讀性比較差啤斗,想使用必須理解其原意

各位看官還可以嗎表箭?喜歡的話,動(dòng)動(dòng)手指點(diǎn)個(gè)贊??钮莲,點(diǎn)個(gè)關(guān)注唄C庾辍!謝謝支持崔拥!
也歡迎關(guān)注公眾號(hào)【Ccww筆記】极舔,原創(chuàng)技術(shù)文章第一時(shí)間推出

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市握童,隨后出現(xiàn)的幾起案子姆怪,更是在濱河造成了極大的恐慌,老刑警劉巖澡绩,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稽揭,死亡現(xiàn)場離奇詭異,居然都是意外死亡肥卡,警方通過查閱死者的電腦和手機(jī)溪掀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來步鉴,“玉大人揪胃,你說我怎么就攤上這事璃哟。” “怎么了喊递?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵随闪,是天一觀的道長。 經(jīng)常有香客問我骚勘,道長铐伴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任俏讹,我火速辦了婚禮当宴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘泽疆。我一直安慰自己户矢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布殉疼。 她就那樣靜靜地躺著梯浪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瓢娜。 梳的紋絲不亂的頭發(fā)上驱证,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音恋腕,去河邊找鬼。 笑死逆瑞,一個(gè)胖子當(dāng)著我的面吹牛荠藤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播获高,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼哈肖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了念秧?” 一聲冷哼從身側(cè)響起淤井,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎摊趾,沒想到半個(gè)月后币狠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砾层,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年漩绵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肛炮。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡止吐,死狀恐怖宝踪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碍扔,我是刑警寧澤瘩燥,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站不同,受9級(jí)特大地震影響厉膀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜套鹅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一站蝠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧卓鹿,春花似錦菱魔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至杰妓,卻和暖如春藻治,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背巷挥。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工桩卵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人倍宾。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓雏节,卻偏偏與公主長得像,于是被迫代替她去往敵國和親高职。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钩乍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容