复习Annotation
注意:注解不同于注释。
- 注释是给开发人员看的,没有任何功能
- 注解是给框架/软件看的,可以赋予注解一些功能
元注解
- 元注解:由JDK提供的,用于限制/修饰自定义注解的注解。常见有的2个:
@Target
:用来限制自定义注解可以用在什么地方。从ElementType
里取值的,常用值有:
-
ElementType.TYPE
:可以用在类、接口上 -
ElementType.METHOD
:可以用在方法上 -
ElementType.FIELD
:可以用在字段(成员变量)上
@Retention
:用来限制自定义注解保留到什么阶段(生命周期)。从RetentionPolicy
里取值,常用的:
-
RetentionPolicy.SOURCE
:保留到源码阶段 -
RetentionPolicy.CLASS
:保留到字节码阶段 -
RetentionPolicy.RUNTIME
:保留到运行阶段
注解的属性
注解的属性,并非所有类型都可以。只支持:
- 8种基本数据类型
- String类型
- Class类型
- 注解类型
- 枚举类型:enum
- 以及以上类型的一维数组形式
自定义注解示例
@Target({ElementType.METHOD, ElementType.FIELD})//可以用在方法上、字段上
@Retention(RetentionPolicy.RUNTIME)//保留到运行阶段
public @interface MyAnno {
String value() default "default value";
String[] abc() default "abc";
}
使用注解
public class Demo02MyAnnoTest {
//不给属性赋值,所有属性使用默认值
@MyAnno
private String str1;
//给abc属性赋值aaaa,value属性不赋值(使用默认值)
@MyAnno(abc="aaaa")
private String str2;
//给value属性赋值,abc属性不赋值(使用默认值)。只给value赋值,可以省略"value="不写
@MyAnno("value的值")
private String str3;
//给abc和value两个属性都赋值
@MyAnno(abc = "aaaa", value = "value的值")
private String str4;
@MyAnno(value = "VALUE1", abc = "abcabc")
public void show(){
System.out.println("======show()======");
}
}
为什么要解析注解
- 注解本身是没有任何功能的,仅仅是相当于一个记号(标记)。
- 把注解(记号)标记在某个类上或方法上,在使用反射调用时,可以根据注解上是否有注解,来增加不同的功能代码
解析注解
public class DemoMyAnnoParseTest {
@MyAnno(value = "VALUE1", abc = "abcabc")
public void show(){
System.out.println("======show()======");
}
//如果show方法上有MyAnno注解,并且value值值是"VALUE",则执行show方法;否则不执行
public static void main(String[] args) throws Exception {
DemoMyAnnoParseTest demo = new DemoMyAnnoParseTest();
Class clazz = demo.getClass();
Method method = clazz.getMethod("show");
//判断方法上是否有MyAnno注解
boolean b = method.isAnnotationPresent(MyAnno.class);
if (b) {
//获取方法配置的注解对象
MyAnno myAnno = method.getAnnotation(MyAnno.class);
String value = myAnno.value();
String[] abc = myAnno.abc();
//判断:如果value值是 VALUE,就执行这个方法,否则不执行
if ("VALUE".equals(value)) {
method.invoke(demo);
}
}
}
}
注解原理
注解是给框架/软件看的,可以赋予注解一些功能**
一个注解准确意义上来说,只不过是一种特殊的注释而已,如果没有解析它的代码,它可能连注释都不如。
所以,当我们在SpringMVC里使用注解时,框架会扫描注解,通过反射方法读出注解,然后执行对应的方法。
总结
首先,我们通过键值对的形式可以为注解属性赋值,像这样:@Hello(value = “hello”)。
接着,你用注解修饰某个元素,编译器将在编译期扫描每个类或者方法上的注解,会做一个基本的检查,你的这个注解是否允许作用在当前位置,最后会将注解信息写入元素的属性表。
然后,当你进行反射的时候,虚拟机将所有生命周期在 RUNTIME 的注解取出来放到一个 map 中,并创建一个 AnnotationInvocationHandler 实例,把这个 map 传递给它。
最后,虚拟机将采用 JDK 动态代理机制生成一个目标注解的代理类,并初始化好处理器。
那么这样,一个注解的实例就创建出来了,它本质上就是一个代理类,你应当去理解好 AnnotationInvocationHandler 中 invoke 方法的实现逻辑,这是核心。一句话概括就是,通过方法名返回注解属性值。