Java注解解析以及自定義注解(轉)

前言

隨著springboot的流行,以前基于XML的spring配置用的越來越少,JavaConfig形式使用的越來越多,類似于:

@Configuration
public class AppConfig {    
    @Bean(name="helloBean")
    public HelloWorld helloWorld() {
        return new HelloWorldImpl();
    }   
}

可以看出更多的是基于注解(Annotation)實現的,包括springboot的入口類**Application

@Configuration
@ComponentScan("com.alibaba.trade")
@EnableAutoConfiguration//(exclude = {PageHelperAutoConfiguration.class})
@ServletComponentScan
@EnableTransactionManagement
@EnableDiscoveryClient
@EnableWebMvc
@MapperScan("com.alibaba.trade.shared.mapper")
public class TradeApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(TradeApplication.class, args);
    }
}

Java注解不僅讓我們減少了項目中XML文件,方便了維護,同時也使我們代碼更簡潔。那么項目中我們如何閱讀注解以及如何創造自己的注解呢?

注解說明

Java注解又稱Java標注,是Java語言5.0版本開始支持加入源代碼的特殊語法元數據。為我們在代碼中添加信息提供了一種形式化的方法,使我們可以在稍后某個時刻非常方便的使用這些數據。
Java語言中的類、方法、變量、參數和包等都可以被標注。和Javadoc不同,Java標注可以通過反射獲取注解內容。在編譯器生成類文件時,注解可以被嵌入到字節碼中。Java虛擬機可以保留注解內容,在運行時可以獲取到注解內容。

內置注解

Java 定義了一套注解,共有 7 個,3 個在 java.lang 中,剩下 4 個在 java.lang.annotation 中。
1、作用在代碼的注解是

@Override - 檢查該方法是否是重寫方法。如果發現其父類,或者是引用的接口中并沒有該方法時,會報編譯錯誤。
@Deprecated - 標記過時方法。如果使用該方法,會報編譯警告。
@SuppressWarnings - 指示編譯器去忽略注解中聲明的警告。

2、作用在其他注解的注解(或者說元注解)是:

@Retention - 標識這個注解怎么保存,是只在代碼中,還是編入class文件中,或者是在運行時可以通過反射訪問。
@Documented - 標記這些注解是否包含在用戶文檔中。
@Target - 標記這個注解應該是哪種 Java 成員。
@Inherited - 標記這個注解是繼承于哪個注解類(默認 注解并沒有繼承于任何子類)

3、從 Java 7 開始,額外添加了 3 個注解:

@SafeVarargs - Java 7 開始支持,忽略任何使用參數為泛型變量的方法或構造函數調用產生的警告。
@FunctionalInterface - Java 8 開始支持,標識一個匿名函數或函數式接口。
@Repeatable - Java 8 開始支持,標識某注解可以在同一個聲明上使用多次。

元注解

1、@Retention

@Retention annotation指定標記注釋的存儲方式:

RetentionPolicy.SOURCE - 標記的注釋僅保留在源級別中,并由編譯器忽略。
RetentionPolicy.CLASS - 標記的注釋在編譯時由編譯器保留,但Java虛擬機(JVM)會忽略。
RetentionPolicy.RUNTIME - 標記的注釋由JVM保留,因此運行時環境可以使用它。

2、@Documented

@Documented 注釋表明,無論何時使用指定的注釋,都應使用Javadoc工具記錄這些元素。(默認情況下,注釋不包含在Javadoc中。)有關更多信息,請參閱 Javadoc工具頁面。

3、@Target

@Target 注釋標記另一個注釋,以限制可以應用注釋的Java元素類型。目標注釋指定以下元素類型之一作為其值

ElementType.TYPE 可以應用于類的任何元素。
ElementType.FIELD 可以應用于字段或屬性。
ElementType.METHOD 可以應用于方法級注釋。
ElementType.PARAMETER 可以應用于方法的參數。
ElementType.CONSTRUCTOR 可以應用于構造函數。
ElementType.LOCAL_VARIABLE 可以應用于局部變量。
ElementType.ANNOTATION_TYPE 可以應用于注釋類型。
ElementType.PACKAGE 可以應用于包聲明。
ElementType.TYPE_PARAMETER
ElementType.TYPE_USE

4、@Inherited

@Inherited 注釋表明注釋類型可以從超類繼承。當用戶查詢注釋類型并且該類沒有此類型的注釋時,將查詢類的超類以獲取注釋類型(默認情況下不是這樣)。此注釋僅適用于類聲明。

5、@Repeatable

Repeatable Java SE 8中引入的,@Repeatable注釋表明標記的注釋可以多次應用于相同的聲明或類型使用(即可以重復在同一個類、方法、屬性等上使用)。

自定義注解

Java中自定義注解和創建一個接口相似,自定義注解的格式是以@interface為標志的。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
    /**
     * default extension name
     */
    String value() default "";
}

我們知道java.lang.annotation包中有一個Annotation的接口,它是所有注解類型擴展的公共接口。那我們是否可以直接通過實現該接口來實現自定義注解呢?

import java.lang.annotation.Annotation;
public class MyAnnotation implements Annotation {
    @Override
    public Class<? extends Annotation> annotationType() {
        return null;
    }
}

發現Annotation接口中只有一個annotationType的方法,而且通過源碼的注釋我們可以發現答案是不能。

image

漢譯即為:Annotaion被所有注解類型繼承,但是要注意:手動擴展繼承此接口的接口不會定義注解類型。另請注意,此接口本身不定義注解類型。

使用場景

自定義注解的使用場景很多,我們在造輪子寫框架的過程經常會使用到,例如我最近就遇到了一個業務場景:像一些編輯業務信息的接口,產品要求信息編輯后的新舊值對比,對比的業務功能,我們的實現方式是拿到前端填寫的Form表單(新值)和數據庫中查詢出來的Dto(舊值)通過反射技術獲取到相同屬性字段名,再比較屬性值就可以得出新舊值。得到值之后我們也知道該字段的Dto中的字段名,但是如何將比較得到的新舊值字段的中文名返回給前端呢?例如:

public class Stedent {
        private String name;
        private int age;
        private String sex;
       //省略setter,getter
    }

比較后我們的結果是 name : "xiaoming "-> "daming",age : 24 -> 26。但是我們不能直接將name和age返回給前端,他們需要的格式是:姓名: "xiaoming "-> "daming",年齡 : 24 -> 26。這時候就可以考慮自定義一個注解@FieldName,

@Deprecated
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldName {
    String value() default "";
}

然后將該注解加在屬性字段上面

public class Student {

    @FieldName(value = "姓名")
    private String name;

    @FieldName(value = "年齡")
    private int age;

    @FieldName(value = "性別")
    private String sex;

    //省略setter,getter
}

之后就可以通過反射獲取該字段中文名

// 如果 oldField 屬性值與 newField 屬性值的內容不相同
if (!isEmpty(newValue)) {
    Map<String, Object> map = new HashMap<>();
    String newFieldName = newField.getName();
    if (newField.isAnnotationPresent(ApiModelProperty.class)) {
        ApiModelProperty apiModelPropertyAnno = newField.getAnnotation(ApiModelProperty.class);
        newFieldName = apiModelPropertyAnno.value();
    else if (newField.isAnnotationPresent(FieldName.class)) {
        FieldName fieldNameAnno = newField.getAnnotation(FieldName.class);
        newFieldName = fieldNameAnno.name();
    }
        map.put(FIELD_NAME, newFieldName);
        map.put(OLD_VALUE, oldValue);
        map.put(NEW_VALUE, newValue);
        list.add(map);
}

作  者:JaJian`博кē
出  處:https://www.cnblogs.com/jajian/p/9695055.html#autoid-2-2-0

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373