简单介绍——Java注解的本质

Java注解实际上就是一个继承自java.lang.annotatAnnotation的接口。而其具体的实现就是一个通过JDK代理实现的动态代理类。

如何去验证这一点呢?

1. 编写一个简单注解

java 复制代码
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest {
  String value();

}

再通过cmd进入到该文件所在路径,进行编译与发编译。

2. 编译后用 javap 反编译

bash 复制代码
javac AnnotationTest.java
javap -p AnnotationTest

得到如下结果:

这就说明,注解的实现本质上还是一个接口,继承自java.lang.annotatAnnotation,我们在注解中定义的所谓的'参数'------value,实际上还是接口中的抽象方法。

那么这个怎么去验证注解的具体实现本质上是通过JDK动态代理实现的呢?

我们可以通过运行以下代码:

java 复制代码
package com.company.annotation;

import java.lang.reflect.Proxy;

@AnnotationTest("hash-yang")
class Demo{

}

public class AnnotationDemo {

  public static void main(String[] args) {
    //设置 JDK 会把所有动态生成的代理类字节码保存到当前目录(根目录)
    System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
    AnnotationTest annotation = Demo.class.getAnnotation(AnnotationTest.class);
    System.out.println(annotation.getClass());
    System.out.println(Proxy.isProxyClass(annotation.getClass()));
  }

}

运行产生以下的目录以及文件:

在其中就是我们这段代码运行时,所有JDK动态代理生成的代理类

proxy0是我们元控制注解的保留策略的注解@Retention的代理类

而$proxy2就是我们的AnnotationTest自定义注解的动态代理类:

java 复制代码
public final class $Proxy1 extends Proxy implements AnnotationTest {
  //其中方法0123都是来自Annotation接口的父类Object的方法,由代理类进行了相应的重写,
  //其中方法3就是实现的返回我们定义的参数值------value的一个函数
  //而方法5就是在Annotation接口中的annotationType,用于返回当前注解的类型(interface com.company.annotation.AnnotationTest)
  private static final Method m0;
  private static final Method m1;
  private static final Method m2;
  private static final Method m3;
  private static final Method m4;

  public $Proxy1(InvocationHandler var1) {
    super(var1);
  }

  public final int hashCode() {
    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 boolean equals(Object var1) {
    try {
      return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
    } catch (RuntimeException | Error var2) {
      throw var2;
    } catch (Throwable var3) {
      throw new UndeclaredThrowableException(var3);
    }
  }

  public final String toString() {
    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 value() {
    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 Class annotationType() {
    try {
      return (Class)super.h.invoke(this, m4, (Object[])null);
    } catch (RuntimeException | Error var2) {
      throw var2;
    } catch (Throwable var3) {
      throw new UndeclaredThrowableException(var3);
    }
  }

  static {
    try {
      m0 = Class.forName("java.lang.Object").getMethod("hashCode");
      m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
      m2 = Class.forName("java.lang.Object").getMethod("toString");
      m3 = Class.forName("com.company.annotation.AnnotationTest").getMethod("value");
      m4 = Class.forName("com.company.annotation.AnnotationTest").getMethod("annotationType");
    } catch (NoSuchMethodException var2) {
      throw new NoSuchMethodError(((Throwable)var2).getMessage());
    } catch (ClassNotFoundException var3) {
      throw new NoClassDefFoundError(((Throwable)var3).getMessage());
    }
  }

  private static MethodHandles.Lookup proxyClassLookup(MethodHandles.Lookup var0) throws IllegalAccessException {
    if (var0.lookupClass() == Proxy.class && var0.hasFullPrivilegeAccess()) {
      return MethodHandles.lookup();
    } else {
      throw new IllegalAccessException(var0.toString());
    }
  }
}

最终注解中的方法的调用都会走到AnnotationInvocationHandler的invoke方法。

相关推荐
兮兮能吃能睡1 小时前
R语言模型分析(一)(1)
开发语言·r语言
兔兔爱学习兔兔爱学习1 小时前
Spring Al学习7:ImageModel
java·学习·spring
lang201509282 小时前
Spring远程调用与Web服务全解析
java·前端·spring
wuk9983 小时前
基于有限差分法的二维平面热传导模型MATLAB实现
开发语言·matlab·平面
m0_564264183 小时前
IDEA DEBUG调试时如何获取 MyBatis-Plus 动态拼接的 SQL?
java·数据库·spring boot·sql·mybatis·debug·mybatis-plus
崎岖Qiu3 小时前
【设计模式笔记06】:单一职责原则
java·笔记·设计模式·单一职责原则
Hello.Reader3 小时前
Flink ExecutionConfig 实战并行度、序列化、对象重用与全局参数
java·大数据·flink
熊小猿4 小时前
在 Spring Boot 项目中使用分页插件的两种常见方式
java·spring boot·后端
paopaokaka_luck4 小时前
基于SpringBoot+Vue的助农扶贫平台(AI问答、WebSocket实时聊天、快递物流API、协同过滤算法、Echarts图形化分析、分享链接到微博)
java·vue.js·spring boot·后端·websocket·spring
老华带你飞4 小时前
机器人信息|基于Springboot的机器人门户展示系统设计与实现(源码+数据库+文档)
java·数据库·spring boot·机器人·论文·毕设·机器人门户展示系统