目录
使用方式简介
新建注解类
package com.aya;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Star {
String value() default "hello";
}
新建被注解标注的类
@Star
public class Student {
}
新建测试方法
@Test
public void test(){
Student student = new Student();
Star annotation = Student.class.getAnnotation(Star.class);
System.out.println(annotation.value());
}
控制台输出: hello
注解是什么
用 javap -c -p com/aya/Star
public interface com.aya.Star extends java.lang.annotation.Annotation {
public abstract java.lang.String value();
}
得出结论:注解就是一个继承 Annotation 的一个接口
注解的实现类是什么
在本例中,注解的对象是通过 Student.class.getAnnotation(Star.class); 获取到的
也就是分析 Class.getAnnotation 如何创建注解接口的实现类的对象的
第一节
1.1 获取Annotation
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
return (A) annotationData().annotations.get(annotationClass);
}
- 这里首先验证 annotationClass 不为 null
- 获取 java.lang.reflect.Class.AnnotationData 内部类 实例
- 用 AnnotationData 实例的 (Map对象)annotations 获取 key
也就是说 在执行 annotationData() 的时候,对象已经创建完成了
在第一阶段,就需要找到 annotationData().annotations 在哪里赋值的就结束了
1.2 获取AnnotationData
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;
}
}
}
- 当前Class实例的annotationData 不为空就返回
- 为空就创建 newAnnotationData
- 原子替换this.annotationData = newAnnotationData,替换成功就返回 newAnnotationData
第一次获取注解时 this.annotationData 一定为null,当获取某个注解之后, this.annotationData 被填充
接下来就分析如何创建注解数据 createAnnotationData(classRedefinedCount);
1.3 创建AnnotationData
private AnnotationData createAnnotationData(int classRedefinedCount) {
Map<Class<? extends Annotation>, Annotation> declaredAnnotations =
AnnotationParser.parseAnnotations(getRawAnnotations(), getConstantPool(), this);
Class<?> superClass = getSuperclass();
Map<Class<? extends Annotation>, Annotation> annotations = null;
if (superClass != null) {
Map<Class<? extends Annotation>, Annotation> superAnnotations =
superClass.annotationData().annotations;
for (Map.Entry<Class<? extends Annotation>, Annotation> e : superAnnotations.entrySet()) {
Class<? extends Annotation> annotationClass = e.getKey();
if (AnnotationType.getInstance(annotationClass).isInherited()) {
if (annotations == null) { // lazy construction
annotations = new LinkedHashMap<>((Math.max(
declaredAnnotations.size(),
Math.min(12, declaredAnnotations.size() + superAnnotations.size())
) * 4 + 2) / 3
);
}
annotations.put(annotationClass, e.getValue());
}
}
}
if (annotations == null) {
// no inherited annotations -> share the Map with declaredAnnotations
annotations = declaredAnnotations;
} else {
// at least one inherited annotation -> declared may override inherited
annotations.putAll(declaredAnnotations);
}
return new AnnotationData(annotations, declaredAnnotations, classRedefinedCount);
}
上面代码有些长,不过可以分为以下几个步骤去分析
1. AnnotationParser.parseAnnotations 获取 类的所有注解实现Class和注解实现类的映射
2. 获取父类,Student的父类 java.lang.Object
3. 如果父类注解不为空,就遍历父类注解做某事.
4. 从父类获取的注解为空,就返回当前类的所有注解,否则,用用父类的注解map填充自己的注解.
5. 创建 AnnotationData 实例,然后返回
在第4步里面, 父类映射.putAll(子类映射) ,这样的话: 当子类和父类拥有同样的注解时,子类会覆盖父类注解
在第一阶段,我们要获取的注解Class对象和注解的对象的映射 declaredAnnotations 已经获取到了
接下来进入第二阶段: 分析 declaredAnnotations 的来源
第二节
在这里的时候,jdk就已经不提供源码了
我们将 jdk/jre/lib/rt.jar 中的 sun.reflect.annotation.AnnotationParser.class 解压出来
用 java -jar cfr_0_131.jar AnnotationParser.class –methodname parseAnnotations 得到下面的代码
后文不在赘述 cfr 使用方式
2.1 解析注解映射
public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(byte[] arrby, ConstantPool constantPool, Class<?> class_) {
if (arrby == null) {
return Collections.emptyMap();
}
try {
return AnnotationParser.parseAnnotations2(arrby, constantPool, class_, null);
}
catch (BufferUnderflowException bufferUnderflowException) {
throw new AnnotationFormatError("Unexpected end of annotations.");
}
catch (IllegalArgumentException illegalArgumentException) {
throw new AnnotationFormatError(illegalArgumentException);
}
}
当注解 Star 没有加入注解: @Retention(RetentionPolicy.RUNTIME) 时,参数 arrby 为 null
2.2 这里仅仅是进行操作之前做了验证和异常捕获,接着分析 parseAnnotations2
private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(byte[] paramArrayOfByte, ConstantPool paramConstantPool, Class<?> paramClass, Class<? extends Annotation>[] paramArrayOfClass)
{
LinkedHashMap localLinkedHashMap = new LinkedHashMap();
ByteBuffer localByteBuffer = ByteBuffer.wrap(paramArrayOfByte);
int i = localByteBuffer.getShort() & 0xFFFF;
for (int j = 0; j < i; j++)
{
Annotation localAnnotation = parseAnnotation2(localByteBuffer, paramConstantPool, paramClass, false, paramArrayOfClass);
if (localAnnotation != null)
{
Class localClass = localAnnotation.annotationType();
if ((AnnotationType.getInstance(localClass).retention() == RetentionPolicy.RUNTIME) &&
(localLinkedHashMap.put(localClass, localAnnotation) != null)) {
throw new AnnotationFormatError("Duplicate annotation for class: " + localClass + ": " + localAnnotation);
}
}
}
return localLinkedHashMap;
}
到这里就找到了 Map 的实现类 LinkedHashMap
那么它的值又依赖 parseAnnotation2 的返回结果 localAnnotation
接下来进行第三阶段的分析: Annotation 对象的获取
第三节
3.1 解析注解映射
private static Annotation parseAnnotation2(ByteBuffer byteBuffer, ConstantPool constantPool, Class<?> class_, boolean bl, Class<? extends Annotation>[] arrclass) {
int n = byteBuffer.getShort() & 65535;
Class<?> class_2 = null;
String string = "[unknown]";
try {
try {
string = constantPool.getUTF8At(n);
class_2 = AnnotationParser.parseSig(string, class_);
}
catch (IllegalArgumentException illegalArgumentException) {
class_2 = constantPool.getClassAt(n);
}
}
catch (NoClassDefFoundError noClassDefFoundError) {
if (bl) {
throw new TypeNotPresentException(string, noClassDefFoundError);
}
AnnotationParser.skipAnnotation(byteBuffer, false);
return null;
}
catch (TypeNotPresentException typeNotPresentException) {
if (bl) {
throw typeNotPresentException;
}
AnnotationParser.skipAnnotation(byteBuffer, false);
return null;
}
if (arrclass != null && !AnnotationParser.contains(arrclass, class_2)) {
AnnotationParser.skipAnnotation(byteBuffer, false);
return null;
}
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(class_2);
}
catch (IllegalArgumentException illegalArgumentException) {
AnnotationParser.skipAnnotation(byteBuffer, false);
return null;
}
Map<String, Class<?>> map = annotationType.memberTypes();
LinkedHashMap<String, Object> linkedHashMap = new LinkedHashMap<String, Object>(annotationType.memberDefaults());
int n2 = byteBuffer.getShort() & 65535;
for (int i = 0; i < n2; ++i) {
int n3 = byteBuffer.getShort() & 65535;
String string2 = constantPool.getUTF8At(n3);
Class<?> class_3 = map.get(string2);
if (class_3 == null) {
AnnotationParser.skipMemberValue(byteBuffer);
continue;
}
Object object = AnnotationParser.parseMemberValue(class_3, byteBuffer, constantPool, class_);
if (object instanceof AnnotationTypeMismatchExceptionProxy) {
((AnnotationTypeMismatchExceptionProxy)object).setMember(annotationType.members().get(string2));
}
linkedHashMap.put(string2, object);
}
return AnnotationParser.annotationForMap(class_2, linkedHashMap);
}
这段代码比较长, 再次分为多个阶段进行解读
3.1.1 创建注解Class对象
try {
try {
string = constantPool.getUTF8At(n);
class_2 = AnnotationParser.parseSig(string, class_);
}
catch (IllegalArgumentException illegalArgumentException) {
class_2 = constantPool.getClassAt(n);
}
}
catch (NoClassDefFoundError noClassDefFoundError) {
if (bl) {
throw new TypeNotPresentException(string, noClassDefFoundError);
}
AnnotationParser.skipAnnotation(byteBuffer, false);
return null;
}
catch (TypeNotPresentException typeNotPresentException) {
if (bl) {
throw typeNotPresentException;
}
AnnotationParser.skipAnnotation(byteBuffer, false);
return null;
}
if (arrclass != null && !AnnotationParser.contains(arrclass, class_2)) {
AnnotationParser.skipAnnotation(byteBuffer, false);
return null;
}
获取Class对象
1. 从常量池中获取指定位置的类文件名,本例为: Lcom/aya/Star;
2. 通过类文件名创建Class对象
3.1.2 获取AnnotationType对象,获得注解默认值
AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(class_2);
}
catch (IllegalArgumentException illegalArgumentException) {
AnnotationParser.skipAnnotation(byteBuffer, false);
return null;
}
通过Class对象创建接口 com.aya.Star的实例
1. 通过Class 获取 AnnotationType 的实例
2. 获取注解的所有方法和默认值的Map映射
3.1.3 覆盖注解默认值
Map<String, Class<?>> map = annotationType.memberTypes();
LinkedHashMap<String, Object> linkedHashMap = new LinkedHashMap<String, Object>(annotationType.memberDefaults());
int n2 = byteBuffer.getShort() & 65535;
for (int i = 0; i < n2; ++i) {
int n3 = byteBuffer.getShort() & 65535;
String string2 = constantPool.getUTF8At(n3);
Class<?> class_3 = map.get(string2);
if (class_3 == null) {
AnnotationParser.skipMemberValue(byteBuffer);
continue;
}
Object object = AnnotationParser.parseMemberValue(class_3, byteBuffer, constantPool, class_);
if (object instanceof AnnotationTypeMismatchExceptionProxy) {
((AnnotationTypeMismatchExceptionProxy)object).setMember(annotationType.members().get(string2));
}
linkedHashMap.put(string2, object);
}
- 确保buffer 在short 范围内 ( int 类型的任意值 & 0xFFFF 一定是一个short 值)
- 从常量池获取指定位置的内容(获取用户赋值的方法名)
- 获取方法返回值类型
- AnnotationParser.parseMemberValue 获取用户设置的值
- 覆盖默认值
3.2 创建实现类Proxy
public static Annotation annotationForMap(final Class<? extends Annotation> class_, final Map<String, Object> map) {
return (Annotation)AccessController.doPrivileged(new PrivilegedAction<Annotation>(){
@Override
public Annotation run() {
return (Annotation)Proxy.newProxyInstance(class_.getClassLoader(), new Class[]{class_}, new AnnotationInvocationHandler(class_, map));
}
});
}
通过Proxy创建动态代理
本例中,newProxyInstance 的三个参数
1. classLoader: AppClassLoader
2. interfaces: com.aya.Star
3. invocationHandler: AnnotationInvocationHandler
直到这里才能得出结论: 注解的实现类是Proxy的子类
本文只是注解详解,并不是动态代理详解,所以这里不进行如何创建代理对象的分析
注解如何执行方法
在创建注解对象的时候,通过构造器,传入注解的 Class对象和 (方法名和值)的一个Map
构造
AnnotationInvocationHandler(Class<? extends Annotation> paramClass, Map<String, Object> paramMap)
{
Class[] arrayOfClass = paramClass.getInterfaces();
if ((!paramClass.isAnnotation()) || (arrayOfClass.length != 1) || (arrayOfClass[0] != Annotation.class))
{
throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
}
type = paramClass;
memberValues = paramMap;
}
- 存储注解的Class对象
- 存储注解解析后的
方法名和值
的Map
在经历了 第三节-3.1.3 之后这里得到的已经是用户设置的值了
执行
解析AnnotationInvocationHandler 的invoke
public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) {
String str = paramMethod.getName();
Class[] arrayOfClass = paramMethod.getParameterTypes();
if ((str.equals("equals")) && (arrayOfClass.length == 1) && (arrayOfClass[0] == Object.class))
{
return equalsImpl(paramArrayOfObject[0]);
}
if (arrayOfClass.length != 0) {
throw new AssertionError("Too many parameters for an annotation method");
}
Object localObject = str;
int i = -1;
switch (((String)localObject).hashCode()) {
case -1776922004:
if (((String)localObject).equals("toString")) i = 0; break;
case 147696667:
if (((String)localObject).equals("hashCode")) i = 1; break;
case 1444986633:
if (((String)localObject).equals("annotationType")) i = 2; break;
}
switch (i) {
case 0:
return toStringImpl();
case 1:
return Integer.valueOf(hashCodeImpl());
case 2:
return type;
}
localObject = memberValues.get(str);
if (localObject == null) {
throw new IncompleteAnnotationException(type, str);
}
if ((localObject instanceof ExceptionProxy)) {
throw ((ExceptionProxy)localObject).generateException();
}
if ((localObject.getClass().isArray()) && (Array.getLength(localObject) != 0)) {
localObject = cloneArray(localObject);
}
return localObject;
}
方法调用分以下四种情况
1. equals 内置处理
2. hashCode 内置处理
3. annotationType 返回注解的Class对象
4. 用户自定义方法时: 获取方法名对应的值
内置处理
toStringImpl
private String toStringImpl() {
StringBuilder stringBuilder = new StringBuilder(128);
stringBuilder.append('@');
stringBuilder.append(this.type.getName());
stringBuilder.append('(');
boolean bl = true;
for (Map.Entry<String, Object> entry : this.memberValues.entrySet()) {
if (bl) {
bl = false;
} else {
stringBuilder.append(", ");
}
stringBuilder.append(entry.getKey());
stringBuilder.append('=');
stringBuilder.append(AnnotationInvocationHandler.memberValueToString(entry.getValue()));
}
stringBuilder.append(')');
return stringBuilder.toString();
}
按照 @(key=value,key1=value1) 的形式,返回注解的所有方法名和返回值
hashCodeImpl
private int hashCodeImpl() {
int n = 0;
for (Map.Entry<String, Object> entry : this.memberValues.entrySet()) {
n += 127 * entry.getKey().hashCode() ^ AnnotationInvocationHandler.memberValueHashCode(entry.getValue());
}
return n;
}
用 127*key1.hashCode+value1.hashCode + 127*key2.hashCode+value2.hashCode ...
的形式,生成一个hashCode
总结
疑问
- 为什么在自定义注解上加: @Retention(RetentionPolicy.RUNTIME) ,参见: 2.1 解析注解映射
结论
- 注解是一个接口
- 注解的使用JDK动态代理创建对象,最终调用 AnnotationInvocationHandler.invoke
- 必须要加入 @Retention(RetentionPolicy.RUNTIME),才能在运行时获取到值,否则会返回null