https://www.cnblogs.com/youzhibing/p/11031216.html(转 @Autowired工作原理)
注解(Annotation)不是程序本身,但是可以对程序作出解释,同时注解还可以让其他程序读取。我们可以把注解加在包(package)、类(class)、方法(method)和变量(field)的上面。
注解是一个接口,一个继承自Annotation的接口。 里面每一个属性,其实就是接口的一个抽象方法
一、内置注解
1、@Override
定义在 java.lang.Override 中 , 此注释只适用于修辞方法 , 表示一个方法声明打算 重写超类中的另一个方法声明,简单来说就是子类在重写父类方法的时候可以加上这个注解。
2、@Deprecated
定义在java.lang.Deprecated中 , 此注释可以用于修辞方法 , 属性 , 类 , 表示不 鼓励程序员使用这样的元素 , 通常是因为它很危险或者存在更好的选择 。即是此方法已经过时,不推使用。
3、@SuppressWarnings
定义在 java.lang.SuppressWarnings 中,用来抑制编译时的警告信息,与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数都是已经定义好了的, 我们选择性的使用就好了 ,一般我们使用 @SuppressWarnings(“all”)
二、元注解
除了 Java 中为我们定义好的注解,我们还可以自定义注解, Java定义了4个标准的元注解(meta-annotation)类型,他们被用来 提供对其他注解类型作说明 。
@Retention(标明注解被保留的阶段)
注解@Retention可以用来修饰注解,是注解的注解,称为元注解。
Retention注解有一个属性value,是RetentionPolicy类型的,Enum RetentionPolicy是一个枚举类型,
这个枚举决定了Retention注解应该如何去保持,也可理解为Rentention 搭配 RententionPolicy使用。RetentionPolicy有3个值:CLASS RUNTIME SOURCE
按生命周期来划分可分为3类:
@Retention:注解的保留位置
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
这3个生命周期分别对应于:Java源文件(.java文件) ---> .class文件 ---> 内存中的字节码。
那怎么来选择合适的注解生命周期呢?
首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。
一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解,比如@Deprecated使用RUNTIME注解
如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;
如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,使用SOURCE 注解。
注解@Override用在方法上,当我们想重写一个方法时,在方法上加@Override,当我们方法的名字出错时,编译器就会报错
注解@Deprecated,用来表示某个类或属性或方法已经过时,不想别人再用时,在属性和方法上用@Deprecated修饰
注解@SuppressWarnings用来压制程序中出来的警告,比如在没有用泛型或是方法已经过时的时候
@Target(标明注解使用的范围)
Target说明的是Annotation所修饰的对象范围
@Target:注解的作用目标
@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
@Inherited(标明注解可继承)
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类
当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。
如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,
直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
@Documented(标明是否生成javadoc文档)
@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员
三、自定义注解
3.1自定义一个Log注解
package com.test.mybatisplus.aop;
import java.lang.annotation.*;
/**
* @Description 日志注解
* @project
* @author:hf
* @date:
* @company:人生有限公司
*/
@Target({ElementType.PARAMETER,ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/**
* 要执行的操作类型比如:add操作
**/
public String operationType() default "";
/**
* 要执行的具体操作比如:添加用户
**/
public String operationName() default "";
}
3.2注解使用
package com.test.mybatisplus.controller;
import com.test.mybatisplus.aop.Log;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
@Api
@RestController
@RequestMapping("aopController")
@Slf4j
@Log(operationType="aopController",operationName="aopControllerT")
public class AopController {
@Log(operationType="aaa",operationName="aaaT")
public String aaa="ds";
@GetMapping("/testAOP")
@ApiOperation(value = "testAOP",notes = "testAOP")
@Log(operationType="testAOP",operationName="测试接口")
public String testAOP() {
return "测试testAOP接口...";
}
public static void main(String[] args) throws Exception{
//类
AopController.class.getAnnotation(Log.class);
AopController.class.getAnnotations();
AopController.class.getDeclaredAnnotations();
AopController.class.getAnnotationsByType(Log.class);
AopController.class.getDeclaredAnnotation(Log.class);
AopController.class.getDeclaredAnnotationsByType(Log.class);
//方法
AopController.class.getMethod("testAOP").getAnnotation(Log.class);
AopController.class.getMethod("testAOP").getAnnotations();
AopController.class.getMethod("testAOP").getDeclaredAnnotations();
AopController.class.getMethod("testAOP").getAnnotationsByType(Log.class);
AopController.class.getMethod("testAOP").getDeclaredAnnotation(Log.class);
AopController.class.getMethod("testAOP").getDeclaredAnnotationsByType(Log.class);
//变量
AopController.class.getField("aaa").getAnnotation(Log.class);
AopController.class.getField("aaa").getAnnotations();
AopController.class.getField("aaa").getDeclaredAnnotations();
AopController.class.getField("aaa").getAnnotationsByType(Log.class);
AopController.class.getField("aaa").getDeclaredAnnotation(Log.class);
AopController.class.getField("aaa").getDeclaredAnnotationsByType(Log.class);
}
}
3.3
AopController.class.getAnnotation(Log.class);
3.4运行方法
AnnotationInvocationHandler 实现InvocationHandler,而InvocationHandler是实现动态代理必须的类(自行了解jdk动态代理)
3.5查看源码,如何生成代理类
通过Log logTest= AopController.class.getAnnotation(Log.class); 进入到class.java getAnnotation方法
@SuppressWarnings("unchecked")
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
return (A) annotationData().annotations.get(annotationClass);
}
private AnnotationData annotationData() {
while (true) { // retry loop
AnnotationData annotationData = this.annotationData;
int classRedefinedCount = this.classRedefinedCount;
if (annotationData != null &&
annotationData.redefinedCount == classRedefinedCount) {
return annotationData;
}
// null or stale annotationData -> optimistically create new instance
AnnotationData newAnnotationData = createAnnotationData(classRedefinedCount);
// try to install it
if (Atomic.casAnnotationData(this, annotationData, newAnnotationData)) {
// successfully installed new AnnotationData
return newAnnotationData;
}
}
}
private AnnotationData createAnnotationData(int classRedefinedCount) {
Map<Class<? extends Annotation>, Annotation> declaredAnnotations =
AnnotationParser.parseAnnotations(getRawAnnotations(), getConstantPool(), this);
Class<?> superClass = getSuperclass();
......
return new AnnotationData(annotations, declaredAnnotations, classRedefinedCount);
}
public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(byte[] var0, ConstantPool var1, Class<?> var2) {
if (var0 == null) {
return Collections.emptyMap();
} else {
try {
return parseAnnotations2(var0, var1, var2, (Class[])null);
} catch (BufferUnderflowException var4) {
throw new AnnotationFormatError("Unexpected end of annotations.");
} catch (IllegalArgumentException var5) {
throw new AnnotationFormatError(var5);
}
}
}
private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(byte[] var0, ConstantPool var1, Class<?> var2, Class<? extends Annotation>[] var3) {
LinkedHashMap var4 = new LinkedHashMap();
ByteBuffer var5 = ByteBuffer.wrap(var0);
int var6 = var5.getShort() & '\uffff';
for(int var7 = 0; var7 < var6; ++var7) {
Annotation var8 = parseAnnotation2(var5, var1, var2, false, var3);
if (var8 != null) {
Class var9 = var8.annotationType();
if (AnnotationType.getInstance(var9).retention() == RetentionPolicy.RUNTIME && var4.put(var9, var8) != null) {
throw new AnnotationFormatError("Duplicate annotation for class: " + var9 + ": " + var8);
}
}
}
private static Annotation parseAnnotation2(ByteBuffer var0, ConstantPool var1, Class<?> var2, boolean var3, Class<? extends Annotation>[] var4) {
......
return annotationForMap(var6, var10);
}
}
public static Annotation annotationForMap(final Class<? extends Annotation> var0, final Map<String, Object> var1) {
return (Annotation)AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
public Annotation run() {
return (Annotation)Proxy.newProxyInstance(var0.getClassLoader(), new Class[]{var0}, new AnnotationInvocationHandler(var0, var1));
}
});
}
最后进入的annotationForMap 就是实现jdk动态代理的代码
public static Annotation annotationForMap(final Class<? extends Annotation> var0, final Map<String, Object> var1) {
return (Annotation)AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
public Annotation run() {
return (Annotation)Proxy.newProxyInstance(var0.getClassLoader(), new Class[]{var0}, new AnnotationInvocationHandler(var0, var1));
}
});
}
3.6下面六个方法执行到最后都会用到动态代理
java的反射包中获取一个元素(Class、 Method、Constructor、Field)上的注解对象主要有6个方法获取的都是运行时注解。
getAnnotation(Class<T> annotationClass)、
getAnnotations()、
getAnnotationsByType(Class<T> annotationClass)、
getDeclaredAnnotation(Class<T> annotationClass)、
getDeclaredAnnotations()、
getDeclaredAnnotationsByType(Class<T> annotationClass)。