注解的基本概念和原理

一、注解:注解的本质就是一个继承了 Annotation 接口的接口
二、JAVA 中有以下几个『元注解』:
	@Target:	注解的作用目标
	@Retention:注解的生命周期
	@Documented:注解是否应当被包含在 JavaDoc 文档中
	@Inherited:是否允许子类继承该注解
		1.其中,@Target 用于指明被修饰的注解最终可以作用的目标是谁,也就是指明,你的注解到底是用来修饰方法的?修饰类的?还是用来修饰字段属性的
			例如:@Target(value = {ElementType.FIELD})
					ElementType.TYPE: 				允许被修饰的注解作用在类、接口和枚举上
					ElementType.FIELD: 				允许作用在属性字段上
					ElementType.METHOD:   			允许作用在方法上
					ElementType.PARAMETER:  		允许作用在方法参数上
					ElementType.CONSTRUCTOR:		允许作用在构造器上
					ElementType.LOCAL_VARIABLE:		允许作用在本地局部变量上
					ElementType.ANNOTATION_TYPE:	允许作用在注解上
					ElementType.PACKAGE:			允许作用在包上
		2.@Retention 用于指明当前注解的生命周期,用法如下
			例如:@Retention(value = RetentionPolicy.RUNTIME
		 			RetentionPolicy.SOURCE:		当前注解编译期可见,不会写入 class 文件
					RetentionPolicy.CLASS:		类加载阶段丢弃,会写入 class 文件
					RetentionPolicy.RUNTIME:	永久保存,可以反射获取
			@Retention 注解指定了被修饰的注解的生命周期,一种是只能在编译期可见,编译后会被丢弃,一种会被编译器编译进 class 文件中,无论是类或是方法,乃至字段,他们都是有属性表的,而 JAVA 
虚拟机也定义了几种注解属性表用于存储注解信息,但是这种可见性不能带到方法区,类加载时会予以丢弃,最后一种则是永久存在的可见性
		简单解析:springboot的启动注解
				 @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 = Configuration.class)
				 	boolean proxyBeanMethods() default true;
				 	....
				 }
三、注解与反射
1.对于一个类或者接口来说,Class 类中提供了以下一些方法用于反射注解。
	getAnnotation:返回指定的注解
	isAnnotationPresent:判定当前元素是否被指定注解修饰
	getAnnotations:返回所有的注解
	getDeclaredAnnotation:返回本元素的指定注解
	getDeclaredAnnotations:返回本元素的所有注解,不包含父类继承而来的
2.注解本质上是继承了 Annotation 接口的接口,而当你通过反射,也就是我们这里的 getAnnotation 方法去获取一个注解类实例的时候,其实 JDK 是通过动态代理机制生成一个实现我们注解(接口)的代理类 代理类实现接口 Hello 并重写其所有方法,包括 value 方法以及接口 Hello 从 Annotation 接口继承而来的方法
案例:
    1.自定义一个注解类型Hello
		import java.lang.annotation.ElementType;
		import java.lang.annotation.Retention;
		import java.lang.annotation.RetentionPolicy;
		import java.lang.annotation.Target;
		@Target(value = {ElementType.FIELD,ElementType.METHOD})
		@Retention(value = RetentionPolicy.RUNTIME)
		public @interface Hello {
		    String value();
		}
	2.使用注解类型
		import com.gsau.project01.Annotation.Hello;
		import java.lang.reflect.Method;
		public class test {
		    @Hello("HelloWorld!!!")
		    public static void main(String[] args) throws NoSuchMethodException {
		        Class cls = test.class;
		        Method method = cls.getMethod("main", String[].class);
		        Hello hello = method.getAnnotation(Hello.class);
		        System.out.println(hello.value());   
		    }
		}
	3.执行结果://打印----->HelloWorld!!!
3.最后再总结一下案例反射注解的工作过程:
	1.首先,我们通过键值对的形式可以为注解属性赋值,像这样:@Hello("HelloWorld!!!")。
	2.接着,你用注解修饰某个元素,编译器将在编译期扫描每个类或者方法上的注解,会做一个基本的检查,你的这个注解是否允许作用在当前位置,最后会将注解信息写入元素的属性表。
	3.然后,当你进行反射的时候,虚拟机将所有生命周期在 RUNTIME 的注解取出来放到一个 map 中,并创建一个 AnnotationInvocationHandler 实例,把这个 map 传递给它。
	4.最后,虚拟机将采用 JDK 动态代理机制生成一个目标注解的代理类,并初始化好处理器。那么这样,一个注解的实例就创建出来了,它本质上就是一个代理类,应当去理解好 AnnotationInvocationHandler 中 invoke 
方法的实现逻辑,这是核心。一句话概括就是,通过方法名返回注解属性值

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值