既然注解最后转化为一个接口,注解中定义的注解成员属性会转化为抽象方法,那么最后这些注解成员属性怎么进行赋值的呢?答案就是:为注解对应的接口生成一个实现该接口的动态代理类。直接点说就是:Java通过动态代理的方式生成了一个实现了"注解对应接口"的实例,该代理类实例实现了"注解成员属性对应的方法",这个步骤类似于"注解成员属性"的赋值过程,这样子就可以在程序运行的时候通过反射获取到注解的成员属性(这里注解必须是运行时可见的,也就是使用了@Retention(RetentionPolicy.RUNTIME),另外需要理解JDK原生动态代理和反射相关内容)。
注解对应的动态代理类实例上面一些已经指出了,注解的最底层实现就是一个JDK的动态代理类,而这个动态代理类的生成过程我们完全可以通过Debug跟踪,这里列举一下笔者跟踪整个过程的流水账:
1、Class<?>#getAnnotation(Class<A> annotationClass),通过类型获取注解实例。
2、Class<?>#annotationData(),获取注解的数据。
3、Class<?>#createAnnotationData(int classRedefinedCount),构建注解的数据。
4、AnnotationParser#parseAnnotations(byte[] var0, ConstantPool var1, Class<?> var2),这里已经是sun包下的类,无法看到源码,这个方法用于解析注解,这一步使用到字节码中常量池的索引解析,常量解析完毕会生成一个成员属性键值对作为下一个环节的入参,常量池的解析可以看AnnotationParser#parseMemberValue方法。
5、AnnotationParser#annotationForMap(final Class<? extends Annotation> var0, final Map<String, Object> var1),同样是sun.reflect.annotation.AnnotationParser中的方法,用于生成注解的动态代理类。
注意第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.");
}
}