從理論到應(yīng)用,你需要掌握的Java注解知識都在這里

1.引言

前段時間因為業(yè)務(wù)的需求颜凯,需要對律所的數(shù)據(jù)進行拆分與合并,因為整個系統(tǒng)涉及到大量的業(yè)務(wù)模塊仗扬,為了盡量減少各具體模塊的遷移開發(fā)工作量症概,需要對遷移過程中的共性內(nèi)容進行抽象,從而設(shè)計出一套更通用的遷移框架早芭。

遷移框架在DB層面進行復制彼城,為了更方便的描述表結(jié)構(gòu)及表之間的關(guān)聯(lián),使用了注解進行定義退个,故總結(jié)一下注解相關(guān)的知識募壕。

注解是JDK1.5引入的新特性,是在代碼里面的一種特殊標記语盈,針對這些標記舱馅,我們可以在源碼、編譯或運行時對代碼做特殊處理刀荒。目前很多主流框架都有在使用注解代嗤,如:

JDK里面的注解@Override、@Resource等缠借;

Spring里面使用的注解@Autowired干毅、@Configurable等;

JUnit測試框架里面的@Test泼返、@Before硝逢、@BeforeClass等。

可以說了解注解是我們設(shè)計出優(yōu)雅代碼,通讀各類框架源碼的必備技能趴捅,尤其是在Spring Boot大行其道的今天垫毙。

2.自定義注解

2.1 定義及使用

以下代碼定義了一個注解Table,有一個屬性value用來表示表的名稱拱绑。

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

public @interface Table{

/**

* 表的名稱

*/

String value() default "";

}

以下代碼使用了剛才定義的注解Table综芥,指定了value的屬性值app_matter,因為只有一個屬性猎拨,所以沒有寫全稱value="app_matter"

@Table("app_matter")

public class MatterDefinition {

@Id(value ="pk_id", mode = IdGeneratorMode.UUID)

String id;

}

定義注解的過程中膀藐,還存在很多其他信息,下面的章節(jié)對定義注解中涉及的各個信息進行說明红省。

2.2 元注解

上面在定義注解的過程中额各,使用到了很多其他注解,這種在描述注解的注解吧恃,稱之為元注解虾啦。

@Target

定義當前注解可以使用在什么地方,上面的Table注解Target使用了TYPE痕寓,所以可以應(yīng)用到類傲醉、接口、注解及枚舉中呻率,其他Target的類型還有:

其中TYPE_PARAMETER硬毕、TYPE_USE是1.8的新增特性,因為并沒有提供反射接口獲取處理礼仗,所以該注解一般要開發(fā)者自己實現(xiàn)或第三方開發(fā)工具實現(xiàn)吐咳。

ElementType.TYPE_PARAMETER:

表示該注解可以應(yīng)用到類型參數(shù)的申明中,如:

public <@MyTypeParameterT> void show(Tmessage){}

ElementType.TYPE_USE:

表示該注解可以使用到類型出現(xiàn)的地方元践,如:

MatterDefinition instance = new @MyTypeUse MatterDefinition();韭脊。

@Retention

定義當前注解的保留策略,如:

RetentionPolicy.SOURCE:

表示該注解僅存在源碼中单旁,編譯成class文件后乾蓬,注解信息將丟失,如:@Override注解慎恒。

RetentionPolicy.CLASS:

表示該注解存在編譯后的class文件中,是注解保留策略的默認方式撵渡。

RetentionPolicy.RUNTIME:

表示該注解存在class文件中融柬,并且被jvm加載后還存在,可以使用反射相關(guān)接口進行獲取趋距。

@Documented

定義該注解是否支持導出到j(luò)avadoc文檔中粒氧。

@Inherited

定義該注解是否可以被子類繼承,如:ClassA使用了Inherited注解节腐,ClassB繼承了ClassA外盯,則ClassB可以獲取到該注解摘盆。

2.3 注解元素

上例中的注解Table,定義了元素value

String value() default "";

3.重復注解

Repeatable:重復注解饱苟,JDK1.8引入的新特性孩擂,可以在類或方法等上指定多個相同的注解屬性,這種方式只是一種語法糖箱熬,下面的Demo類中最終生成的注解其實還是Items类垦。

@Target(ElementType.TYPE)

public @interface Items{

Item[] value();

}

@Repeatable(Items.class)

@Target(ElementType.TYPE)

@interface Item{

String value() default "";

}

@Item("item1")

@Item("item2")

class Demo {

? ? public static void main(String[] args) {

? ? }

}

4.注解反射

和注解相關(guān)的接口有Annotation和AnnotatedElement,其中:

所有的注解對象annotation都實現(xiàn)了Annotation接口城须,該對象的annotationType方法返回注解的類型(如:Table.class)蚤认,該對象自身是一個動態(tài)代理對象(如:$Proxy2)。

5.注解的應(yīng)用

5.1 注解屬性的獲取

@Table("app_matter")

class MatterDefinition {

@Id(value ="pk_id", mode = IdGeneratorMode.UUID)

String id;

}

public class AnnotationDemo {

public static void main(String[] args)throws NoSuchFieldException {

System.out.println(MatterDefinition.class.isAnnotationPresent(Table.class));//true

Table tableAnnotation = MatterDefinition.class.getAnnotation(Table.class);

System.out.println(tableAnnotation.value());//app_task

Field idField = MatterDefinition.class.getDeclaredField("id");

Id idAnnotation = idField.getAnnotation(Id.class);

System.out.println(idAnnotation.mode());//IdGeneratorMode.UUID

}

}

5.2 獲取指定包下含有指定注解的類

方式一:原生反射

通過JDK原生的方式進行反射處理糕伐,即獲取到指定包下的所有類砰琢,然后遍歷每個類判斷當前類是否出現(xiàn)指定注解,這種方式相當于從零開始撰寫很多基礎(chǔ)代碼良瞧。

方式二:借助Spring中注解Component的Bean管理

在定義注解(如:Table)的時候加上元注解@Component陪汽,以把使用當前注解的類注冊為Bean對象

從容器ApplicationContext中調(diào)用:Map getBeansWithAnnotation(Class annotationType)

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Component//此處加上Component注解

@interface MyTableAnnotation{

String value() default "";

}

@MyTableAnnotation("app_task")

class TaskDefinition {

@Id(value ="pk_id", mode = IdGeneratorMode.UUID)

String id;

}

@Component

public class ComponentAnnotationDemo implements ApplicationContextAware {

ApplicationContext applicationContext;

@Override

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

this.applicationContext= applicationContext;

}

public void show() {

//獲取容器中指定注解類型的所有Bean對象

Map stringObjectMap =applicationContext.getBeansWithAnnotation(MyTableAnnotation.class);

System.out.println("stringObjectMap:"+ stringObjectMap);

}

}

方式三:借助Spring的包掃描注解ClassPathScanningCandidateComponentProvider

通過ClassPathScanningCandidateComponentProvider掃描指定的包

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@interface MyTableAnnotation{

String value() default "";

}

@MyTableAnnotation("app_task")

class TaskDefinition {

@Id(value ="pk_id", mode = IdGeneratorMode.UUID)

String id;

}

@Component

public class ComponentAnnotationDemo {

public void show() {

//useDefaultFilters:是否掃描默認的Component,Controller,Service,Repository注解

ClassPathScanningCandidateComponentProvider classPathScanningCandidateComponentProvider = new ClassPathScanningCandidateComponentProvider(false);

//以注解的方式作為掃描條件,也可以指定正則(如:RegexPatternTypeFilter)等其他掃描方式

classPathScanningCandidateComponentProvider.addIncludeFilter(newAnnotationTypeFilter(MyTableAnnotation.class));

//basePackage:指定掃描的基礎(chǔ)包莺褒,空字符串為所有包

Set beanDefinitionSet = classPathScanningCandidateComponentProvider.findCandidateComponents("com.icourt");

System.out.println(beanDefinitionSet);

}

}

6.幾個注解的簡單說明

此處簡單列舉幾個注解的說明掩缓,權(quán)當混個臉熟,后期再根據(jù)實際情況遵岩,結(jié)合各框架你辣,進行專題深入講解。

以下三個注解是JDK1.5開始支持注解特性時引入的尘执,也算是鼻祖了舍哄。

Override:表示重寫了父類的指定方法;如果方法上有該注解誊锭,但方法名與超類不同表悬,開發(fā)工具將給出錯誤警告。

Deprecated:表示指定的類或方法已經(jīng)被廢棄丧靡,不建議繼續(xù)使用蟆沫,而應(yīng)該使用新的替代方案。

SuppressWarnings:表示忽略指定類型的警告提示温治。

以下兩個注解是JDK1.8引入的新特性饭庞。

FunctionalInterface:函數(shù)式接口的注解,主要用在Lambda表達式中熬荆,表示該接口只能有一個抽象方法舟山,從而可以使用Lambda表達式進行簡寫。

Repeatable:重復注解,可以在類或方法等上指定多個相同的注解屬性累盗,上面章節(jié)有說明寒矿。

以下三個是通用注解(Common Annotation),原來是Java EE5.0規(guī)范的一部分若债,后面加入到了Java SE6.0中符相,避免框架或各類開發(fā)者重復定義。Java SE里面僅包含了注解類的定義拆座,但沒有包含注解類的解析實現(xiàn)主巍,而是由Java EE容器進行實現(xiàn),如:應(yīng)用到Servlet規(guī)范的生命周期注解挪凑;Spring對這幾個注解也做了解析支持孕索。

Resource:表示一種資源,如果應(yīng)用到屬性或方法上躏碳,則這個類在實例化的時候搞旭,將自動注入該類型或命名的對象。

PostConstruct:表示在對象創(chuàng)建之后做的額外處理菇绵。

PreDestroy:表示在對象銷毀之前做的額外處理肄渗。

以下注解是Spring2.5版本引入的,針對MVC和通用組件的一套注解咬最。

Controller:表示這是一個Controller層對象翎嫡,一般封裝參數(shù)校驗,權(quán)限判斷永乌,及不可復用的簡單邏輯惑申。

Service:表示這是一個業(yè)務(wù)層Bean對象,一般封裝具體的業(yè)務(wù)邏輯翅雏。

Repository:Spring 2.0引入的注解圈驼,對數(shù)據(jù)訪問層的對象進行Bean標示。

Component:表示這是一個Bean對象望几。

Autowired:默認根據(jù)類型自動裝配指定的Bean對象绩脆,如果要按名稱進行裝配,可以結(jié)合Qualifier注解橄抹。

以下兩個注解是Spring3.0為了減少XML配置而引入的基于Java的注解靴迫。

Configuration:表示這是一個配置類,里面會包含一個或多個被Bean標注的方法楼誓,用于Spring創(chuàng)建出Bean的實例矢劲。

Bean:標注的方法可以構(gòu)造出Bean的實例,方法名默認為容器中Bean的名稱慌随。

以下為Spring4.0引入的條件注解。

Conditional:根據(jù)某個條件決定是否創(chuàng)建某個bean,這也是Spring Boot框架實現(xiàn)的基礎(chǔ)阁猜。

7.要點總結(jié)

對前面介紹的內(nèi)容做一張腦圖進行總結(jié)丸逸,方便大家一覽文章的關(guān)鍵要點。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末剃袍,一起剝皮案震驚了整個濱河市黄刚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌民效,老刑警劉巖憔维,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異畏邢,居然都是意外死亡业扒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門舒萎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來程储,“玉大人,你說我怎么就攤上這事臂寝≌吕穑” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵咆贬,是天一觀的道長败徊。 經(jīng)常有香客問我,道長掏缎,這世上最難降的妖魔是什么皱蹦? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮御毅,結(jié)果婚禮上根欧,老公的妹妹穿的比我還像新娘。我一直安慰自己端蛆,他們只是感情好凤粗,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著今豆,像睡著了一般嫌拣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上呆躲,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天异逐,我揣著相機與錄音,去河邊找鬼插掂。 笑死灰瞻,一個胖子當著我的面吹牛腥例,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播酝润,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼燎竖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了要销?” 一聲冷哼從身側(cè)響起构回,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎疏咐,沒想到半個月后纤掸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡浑塞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年借跪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缩举。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡垦梆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出仅孩,到底是詐尸還是另有隱情托猩,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布辽慕,位于F島的核電站京腥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏溅蛉。R本人自食惡果不足惜公浪,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望船侧。 院中可真熱鬧欠气,春花似錦、人聲如沸镜撩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袁梗。三九已至宜鸯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間遮怜,已是汗流浹背淋袖。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锯梁,地道東北人即碗。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓焰情,卻偏偏與公主長得像,于是被迫代替她去往敵國和親剥懒。 傳聞我的和親對象是個殘疾皇子烙样,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)蕊肥,斷路器,智...
    卡卡羅2017閱讀 134,701評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法蛤肌,類相關(guān)的語法壁却,內(nèi)部類的語法,繼承相關(guān)的語法裸准,異常的語法展东,線程的語...
    子非魚_t_閱讀 31,664評論 18 399
  • 本文章涉及代碼已放到github上annotation-study 1.Annotation為何而來 What:A...
    zlcook閱讀 29,185評論 15 116
  • 文章作者:Tyan博客:noahsnail.com 3.4 Dependencies A typical ente...
    SnailTyan閱讀 4,168評論 2 7
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,814評論 0 11