注解中获取属性值的底层原理
2020-06-24 本文已影响0人
码而优则仕
注解中获取属性值的底层原理
Java里面万物皆为对象,注解也不例外,JVM会在运行时为我们生成中间对象。
要获取JVM生成的中间对象,需要修改JVM的启动参数,才能获取到JVM为我们生成的中间对象。
JDK8配置如下命令:
JVMParamSetting.png执行如下程序:
public class AnnotationParser {
//解析类的注解
public static void parseTypeAnnotation() throws Exception {
Class target = Class.forName("com.yuns.demo.annotation.YunsCourse");
System.out.println("=====获取类上注解=======");
Annotation[] annotations = target.getAnnotations();
for (Annotation annotation : annotations) {
CourseInfoAnnotation courseInfoAnnotation = (CourseInfoAnnotation) annotation;
System.out.println("课程名称 :" + courseInfoAnnotation.courseName());
System.out.println("课程标签 :" + courseInfoAnnotation.courseTag());
System.out.println("课程简介 :" + courseInfoAnnotation.courseProfile());
System.out.println("课程序号 :" + courseInfoAnnotation.coursIendex());
}
}
//解析成员变量的注解
public static void parseFieldAnnotation() throws Exception {
Class target = Class.forName("com.yuns.demo.annotation.YunsCourse");
System.out.println("=====获取成员变量上的注解=======");
Field[] fields = target.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(PersonInfoAnnotation.class)) {
PersonInfoAnnotation personInfoAnnotation = (PersonInfoAnnotation) field.getAnnotation(PersonInfoAnnotation.class);
System.out.println("姓名 :" + personInfoAnnotation.name());
System.out.println("年龄 :" + personInfoAnnotation.age());
System.out.println("精通语言 :" + personInfoAnnotation.language());
System.out.println("性别 :" + personInfoAnnotation.gender());
}
}
}
//解析成员方法的注解
public static void parseMethodAnnotation() throws Exception {
Class target = Class.forName("com.yuns.demo.annotation.YunsCourse");
System.out.println("=====获取成员方法上的注解=======");
Method[] methods = target.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(CourseInfoAnnotation.class)) {
CourseInfoAnnotation courseInfoAnnotation = (CourseInfoAnnotation) method.getAnnotation(CourseInfoAnnotation.class);
System.out.println("课程名称 :" + courseInfoAnnotation.courseName());
System.out.println("课程标签 :" + courseInfoAnnotation.courseTag());
System.out.println("课程简介 :" + courseInfoAnnotation.courseProfile());
System.out.println("课程序号 :" + courseInfoAnnotation.coursIendex());
}
}
}
public static void main(String args[]) throws Exception {
// parseTypeAnnotation();
parseFieldAnnotation();
// parseMethodAnnotation();
}
}
会在项目下生成com.sun.proxy文件夹,文件夹下就是JDK运行时动态代理生成的中间对象:
//实现元注解Retention
public final class $Proxy0 extends Proxy implements Retention {
private static Method m1;
private static Method m2;
private static Method m4;
private static Method m0;
private static Method m3;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final Class annotationType() throws {
try {
return (Class)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final RetentionPolicy value() throws {
try {
return (RetentionPolicy)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("java.lang.annotation.Retention").getMethod("annotationType");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m3 = Class.forName("java.lang.annotation.Retention").getMethod("value");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
public final class $Proxy1 extends Proxy implements PersonInfoAnnotation {
private static Method m1;
private static Method m4;
private static Method m3;
private static Method m2;
private static Method m6;
private static Method m5;
private static Method m7;
private static Method m0;
public $Proxy1(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String[] language() throws {
try {
return (String[])super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String name() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String gender() throws {
try {
return (String)super.h.invoke(this, m6, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int age() throws {
try {
return (Integer)super.h.invoke(this, m5, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final Class annotationType() throws {
try {
return (Class)super.h.invoke(this, m7, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.yuns.demo.annotation.PersonInfoAnnotation").getMethod("language");
m3 = Class.forName("com.yuns.demo.annotation.PersonInfoAnnotation").getMethod("name");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m6 = Class.forName("com.yuns.demo.annotation.PersonInfoAnnotation").getMethod("gender");
m5 = Class.forName("com.yuns.demo.annotation.PersonInfoAnnotation").getMethod("age");
m7 = Class.forName("com.yuns.demo.annotation.PersonInfoAnnotation").getMethod("annotationType");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
现在分析注解的工作原理
-
首先通过键值对的形式为注解属性赋值
@CourseInfoAnnotation(courseName = "注解学习", courseTag = "基础"
, courseProfile = "学习注解全面知识")
public class YunsCourse {
@PersonInfoAnnotation(name = "wsq", language = {"Java", "C++"})
private String author;
@CourseInfoAnnotation(courseName = "Java基本知识学习", courseTag = "常识"
, courseProfile = "学习框架必须的知识")
public void getCourseInfo() {
}
}
-
我们用注解修饰某个元素的时候,编译器在编译期扫描类的时候会检查注解的使用范围,然后判断注解添加的位置是否合理;如果合理的话会在Java编译成class文件的时候将注解信息写入元素的属性表。—注解就是在编译器编译的时候进行处理,写入class文件中。
-
运行时JVM将一个类中所有生命周期时RUN的注解属性取出,并放到Map中
-
JVM会创建一个AnnotationInvocationHandler的实例,然后将存储注解属性的Map传递给这个实例
private final Map<String, Object> memberValues;
-
JVM会使用动态代理为注解生成代理类,并初始化处理器(对应的InnovationHandler)。
-
注解被JVM动态代理后,本质上就是一个代理类,通过调用invoke方法,通过传入方法名返回注解对应的属性名