设为首页 加入收藏

TOP

JDK中注解的底层实现(二)
2018-10-10 04:11:27 】 浏览:724
Tags:JDK 注解 底层 实现
p;   Ljava/lang/annotation/ElementType;
  #18 = Utf8              TYPE
  #19 = Utf8              club/throwable/annotation/Counter
  #20 = Utf8              java/lang/Object
  #21 = Utf8              java/lang/annotation/Annotation
{
  public abstract int count();
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_ABSTRACT
    AnnotationDefault:
      default_value: I#7}
SourceFile: "Counter.java"
RuntimeVisibleAnnotations:
  0: #11(#12=e#13.#14)
  1: #15()
  2: #16(#12=[e#17.#18])


如果熟悉字节码,从直观上可以得到下面的信息:


既然注解最后转化为一个接口,注解中定义的注解成员属性会转化为抽象方法,那么最后这些注解成员属性怎么进行赋值的呢?答案就是:为注解对应的接口生成一个实现该接口的动态代理类。直接点说就是:Java通过动态代理的方式生成了一个实现了"注解对应接口"的实例,该代理类实例实现了"注解成员属性对应的方法",这个步骤类似于"注解成员属性"的赋值过程,这样子就可以在程序运行的时候通过反射获取到注解的成员属性(这里注解必须是运行时可见的,也就是使用了@Retention(RetentionPolicy.RUNTIME),另外需要理解JDK原生动态代理和反射相关内容)。


上面一些已经指出了,注解的最底层实现就是一个JDK的动态代理类,而这个动态代理类的生成过程我们完全可以通过Debug跟踪,这里列举一下笔者跟踪整个过程的流水账:


注意第5步,贴出它的源码:


    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));
            }
        });
    }


熟悉JDK动态代理的这里的代码应该看起来很简单,就是生成一个标准的JDK动态代理,而InvocationHandler的实例是AnnotationInvocationHandler,可以看它的成员变量、构造方法和实现InvocationHandler接口的invoke方法:


class AnnotationInvocationHandler implements InvocationHandler, Serializable {
    private static final long serialVersionUID = 6182022883658399397L;
    //保存了当前注解的类型
    private final Class<? extends Annotation> type;
    //保存了注解的成员属性的名称和值的映射,注解成员属性的名称实际上就对应着接口中抽象方法的名称
    private final Map<String, Object> memberValues;
    private transient volatile Method[] memberMethods = null;


    AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2) {
        Class[] var3 = var1.getInterfaces();
        if (var1.isAnnotation() && var3.length == 1 && var3[0] == Annotation.class) {
            this.type = var1;
            this.memberValues = var2;
        } else {
            throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
        }
    }


    public Object invoke(Object var1, Method var2, Object[] var3) {
        //获取当前执行的方法名称
        String var4 = var2.getName();
        Class[] var5 = var2.getParameterTypes();
        if (var4.equals("equals"

首页 上一页 1 2 3 4 5 6 下一页 尾页 2/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇什么是Hibernate延时加载? 下一篇JVM自定义类加载器加载指定classP..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目