JAVA && Spring && SpringBoot2.x — 學(xué)習(xí)目錄
注解可以代替配置文件的功能蟆淀。
1. 元注解
元注解的作用就是注解其他注解赡译,一般我們使用自定義注解時(shí)腊徙,就需要用元注解來(lái)標(biāo)注我們自己的注解拦止,一共有以下四個(gè)元注解鸿脓。
1.1 @Target注解
說(shuō)明Annotation被修飾的范圍犹菇,可被用于packages、type(類闹蒜,接口寺枉,枚舉,Annotation類型)绷落、類型成員(方法姥闪,構(gòu)造方法,成員變量砌烁,枚舉值)筐喳、方法參數(shù)和本地變量(如循環(huán)變量,catch參數(shù))函喉。
一句話總結(jié):定義了注解的作用范圍避归。
使用方法:@Target(ElementType.TYPE)
類型 | 作用域 |
---|---|
ElementType.CONSTRUCTOR | 用于描述構(gòu)造器 |
ElementType.FIELD | 用于描述域(類的成員) |
ElementType.LOCAL_VARIABLE | 用于描述局部變量(方法內(nèi)部變量) |
ElementType.METHOD | 用于描述方法 |
ElementType.PACKAGE | 用于描述包 |
ElementType.PARAMETER | 用于描述參數(shù) |
ElementType.TYPE | 用于描述類、接口(包括注解類型) 或enum聲明 |
1.2 @Retention
[瑞ten神]
定義了該注解被保留的時(shí)間長(zhǎng)短管呵,有些只在源碼中保留梳毙,有些需要編譯成的class中保留,有些需要在程序運(yùn)行時(shí)候保留捐下。
一句話總結(jié):定義注解的聲明周期账锹。
使用方法:@Retention(RetentionPolicy.RUNTIME)
類型 | 作用域 |
---|---|
RetentionPoicy.SOURCE | 在源文件中有效(即源文件保留) |
RetentionPoicy.CLASS | 在class文件中有效(即class保留) |
RetentionPoicy.RUNTIME | 在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留) |
1.3 Documented
標(biāo)記注解萌业,該元注解沒(méi)有屬性。表明這個(gè)注解應(yīng)該被javadoc工具記錄奸柬。即若使用javadoc之類的工具處理生年,該注解信息會(huì)被生成到文檔中。
1.4 Inherited
[in 和 瑞 ti 得]
標(biāo)記注解廓奕,被他標(biāo)記的類型是可繼承的抱婉,比如一個(gè)class被@Inherited標(biāo)記,那么一個(gè)子類繼承該class后桌粉,則這個(gè)注解將被用于該class的子類授段。
自定義注解無(wú)@Inherited | 自定義注解有@Inherited | |
---|---|---|
子類能否繼承父類上的注解 | 否 | 能 |
子類方法,實(shí)現(xiàn)了父類的抽象方法番甩,能否可以繼承注解 | 否 | 否 |
子類方法,繼承了父類方法届搁,能否繼承注解 | 能 | 能 |
子類方法缘薛,覆蓋了父類方法,能否繼承注解 | 否 | 否 |
@MyAnno
public interface Eat {
}
class Parent implements Eat {
}
class Child implements Eat {
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@RequestMapping
@interface MyAnno {
}
class Test {
public static void main(String[] args) {
MyAnno eatAnnotation = Eat.class.getAnnotation(MyAnno.class);
MyAnno parentAnnotation = Parent.class.getAnnotation(MyAnno.class);
MyAnno childAnnotation = Child.class.getAnnotation(MyAnno.class);
System.out.println(eatAnnotation); //@com.galax.common.anno.customAnno.MyAnno()
System.out.println(parentAnnotation); //null
System.out.println(childAnnotation); //null
}
}
我們的注解標(biāo)注了@Inherited表示該注解可以被繼承卡睦,但是parentAnnotation和childAnnotation依舊是null宴胧。需要注意:@Inherited繼承只能發(fā)生在類上,而不發(fā)生在接口上(也就是說(shuō)標(biāo)注在接口上依舊不能被繼承表锻。)
2. 自定義注解
1. 自定義注解的格式
public @interface 注解名 {定義體}
使用@interface定義的一個(gè)注解恕齐,自動(dòng)繼承了java.lang.annotation.Annotation
接口,其中的每一個(gè)方法實(shí)際上是聲明了一個(gè)配置參數(shù)瞬逊。方法的名稱就是參數(shù)的名稱显歧,返回值就是參數(shù)的類型(返回值類型只能是:基本類型、Class确镊、String士骤、enum類型、Annotation類型蕾域,以及上述參數(shù)的數(shù)組類型)拷肌。可以使用default
來(lái)聲明參數(shù)的默認(rèn)值。
2. 需要注意的點(diǎn):
- 只能用public或默認(rèn)(default)這兩個(gè)訪問(wèn)權(quán)修飾旨巷。
- 如果只有一個(gè)參數(shù)成員,最好把參數(shù)名稱設(shè)為"value"巨缘。
- 參數(shù)的返回值,只能是基本類型采呐,String類型若锁,Class類型,枚舉類型斧吐,注解類型以及他們的數(shù)組類型拴清。
3. 注解的默認(rèn)值
注解元素必須有確定的值靶病,要么是給定的默認(rèn)值,要是使用的時(shí)候賦予值口予。需要注意的是:若需要表達(dá)一個(gè)元素不存在值娄周,所以使用空字符串或者負(fù)數(shù)表示某個(gè)元素不存在,在定義注解時(shí)沪停,這已經(jīng)成為一個(gè)約定用法煤辨。
3. 如何獲取自定義注解信息
Java自定義注解是通過(guò)運(yùn)行時(shí)靠反射獲取注解
Java的注解解析類主要是AnnotatedElement接口的實(shí)現(xiàn)類,我們可以通過(guò)反射獲取一個(gè)類的AnnotatedElement對(duì)象后木张,就可以通過(guò)下面表格的幾個(gè)方法众辨,訪問(wèn)Annotation信息。
方法返回值 | 方法 | 方式解釋 |
---|---|---|
T | getAnnotation(Class<T> annotationClass) | 返回元素上存在的舷礼,指定類型的注解鹃彻。如果該類型注解不存在,則返回null妻献。 |
Annotation[] | getAnnotations() | 返回該元素上的所有注解蛛株。 |
T | getDeclaredAnnotation(Class<T> annotationClass) | 返回元素上存在,指定類型的注解育拨,忽略繼承注解谨履,如果該類型注解不存在,則返回null熬丧。 |
Annotation[] | getDeclaredAnnotations() | 返回直接存在于類上的所有注解笋粟,忽略繼承注解,如果該元素上沒(méi)有任何注解析蝴,那么將返回一個(gè)長(zhǎng)度為0的數(shù)組害捕。 |
boolean | isAnnotationPresent(Class<? extends Annotation>) | 判斷程序元素上是否包含指定類型的注解,存在則返回true闷畸,否則返回false吨艇。 |
1. 自定義注解:定義
@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInfo {
String author() default "xioapang";
String date();
int revision() default 1;
String comments();
}
2. 自定義注解:使用
public class AnnotationExample {
@MethodInfo(author = "XXX", comments = "toString method", date = "Nov 17 2019", revision = 2)
public String toString() {
return "Overriden toString method";
}
}
3. 自定義注解:解析
@Slf4j
public class AnnotationParsing {
public static void main(String[] args) {
try {
//加載某個(gè)類上的所有方法
for (Method method : AnnotationParsing.class.getClassLoader().loadClass("com.galax.common.anno.customAnno.AnnotationExample").getMethods()) {
//判斷方法是否存在MethodInfo.class注解
if (method.isAnnotationPresent(MethodInfo.class)) {
//獲取非繼承關(guān)系的所有注解
for (Annotation anno : method.getDeclaredAnnotations()) {
log.info("注解信息:{} ", anno);
}
//獲取元素上該注解的詳細(xì)信息
MethodInfo methodAnnotation = method.getAnnotation(MethodInfo.class);
log.info("版本號(hào):{}", methodAnnotation.revision());
log.info("作者:{}", methodAnnotation.author());
log.info("時(shí)間:{}", methodAnnotation.date());
log.info("描述:{}", methodAnnotation.comments());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}