一文讀懂注解的底層原理

點擊上方老周聊架構(gòu)關(guān)注我
一、前言
注解類型聲明中的標(biāo)識符指定了注解類型的名稱。
如果注解類型與它的任何封閉類或接口具有相同的簡單名稱,則編譯時會出現(xiàn)錯誤。
每個注解類型的直接父接口都是 java.lang.annotation.Annotation。
二、注解的底層實現(xiàn)
(RetentionPolicy.RUNTIME)(ElementType.TYPE)public RateLimit {int value() default 0;}
@RateLimit(value = 666)public class RateLimitMain {public static void main(String[] args) {RateLimit rateLimit = RateLimitMain.class.getAnnotation(RateLimit.class);System.out.println(rateLimit.value());}}
javap -c -v RateLimit.classClassfile /Users/Riemann/Code/spring-boot-demo/target/classes/com/riemann/springbootdemo/annotation/RateLimit.classLast modified 2021-3-23; size 495 bytesMD5 checksum 1ce59bd6cc4c7297e8d3f032320b04d3Compiled from "RateLimit.java"public interface com.riemann.springbootdemo.annotation.RateLimit extends java.lang.annotation.Annotationminor version: 0major version: 52flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATIONConstant pool:#1 = Class #18 // com/riemann/springbootdemo/annotation/RateLimit#2 = Class #19 // java/lang/Object#3 = Class #20 // java/lang/annotation/Annotation#4 = Utf8 value#5 = Utf8 ()I#6 = Utf8 AnnotationDefault#7 = Integer 0#8 = Utf8 SourceFile#9 = Utf8 RateLimit.java#10 = Utf8 RuntimeVisibleAnnotations#11 = Utf8 Ljava/lang/annotation/Retention;#12 = Utf8 Ljava/lang/annotation/RetentionPolicy;#13 = Utf8 RUNTIME#14 = Utf8 Ljava/lang/annotation/Documented;#15 = Utf8 Ljava/lang/annotation/Target;#16 = Utf8 Ljava/lang/annotation/ElementType;#17 = Utf8 TYPE#18 = Utf8 com/riemann/springbootdemo/annotation/RateLimit#19 = Utf8 java/lang/Object#20 = Utf8 java/lang/annotation/Annotation{public abstract int value();descriptor: ()Iflags: ACC_PUBLIC, ACC_ABSTRACTAnnotationDefault:default_value: I#7}SourceFile: "RateLimit.java"RuntimeVisibleAnnotations:0: #11(#4=e#12.#13)1: #14()2: #15(#4=[e#16.#17])
注解是一個接口,它繼承自 java.lang.annotation.Annotation 父接口。
@RateLimit 自身定義了一個抽象方法 public abstract int value(); 。
三、揭秘注解背后的代理類
public final class Class<T> implements java.io.Serializable,GenericDeclaration,Type,AnnotatedElement {...}
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {Objects.requireNonNull(annotationClass);return (A) annotationData().annotations.get(annotationClass);}
// annotation data that might get invalidated when JVM TI RedefineClasses() is calledprivate static class AnnotationData {final Map<Class<? extends Annotation>, Annotation> annotations;final Map<Class<? extends Annotation>, Annotation> declaredAnnotations;// Value of classRedefinedCount when we created this AnnotationData instancefinal int redefinedCount;AnnotationData(Map<Class<? extends Annotation>, Annotation> annotations,Map<Class<? extends Annotation>, Annotation> declaredAnnotations,int redefinedCount) {this.annotations = annotations;this.declaredAnnotations = declaredAnnotations;this.redefinedCount = redefinedCount;}}
private AnnotationData annotationData() {while (true) { // retry loopAnnotationData annotationData = this.annotationData;int classRedefinedCount = this.classRedefinedCount;if (annotationData != null &&annotationData.redefinedCount == classRedefinedCount) {return annotationData;}// null or stale annotationData -> optimistically create new instanceAnnotationData newAnnotationData = createAnnotationData(classRedefinedCount);// try to install itif (Atomic.casAnnotationData(this, annotationData, newAnnotationData)) {// successfully installed new AnnotationDatareturn newAnnotationData;}}}
static <T> boolean casAnnotationData(Class<?> clazz,AnnotationData oldData,AnnotationData newData) {return unsafe.compareAndSwapObject(clazz, annotationDataOffset, oldData, newData);}
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 constructionannotations = 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 declaredAnnotationsannotations = declaredAnnotations;} else {// at least one inherited annotation -> declared may override inheritedannotations.putAll(declaredAnnotations);}return new AnnotationData(annotations, declaredAnnotations, classRedefinedCount);}
獲取類本身的 declaredAnnotations
獲取父類的 annotations
將 declaredAnnotations+annotations 整合,返回
public static Object parseMemberValue(Class<?> var0, ByteBuffer var1, ConstantPool var2, Class<?> var3) {Object var4 = null;byte var5 = var1.get();switch(var5) {case 64:var4 = parseAnnotation(var1, var2, var3, true);break;case 91:return parseArray(var0, var1, var2, var3);case 99:var4 = parseClassValue(var1, var2, var3);break;case 101:return parseEnumValue(var0, var1, var2, var3);default:var4 = parseConst(var5, var1, var2);}if (!(var4 instanceof ExceptionProxy) && !var0.isInstance(var4)) {var4 = new AnnotationTypeMismatchExceptionProxy(var4.getClass() + "[" + var4 + "]");}return var4;}
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));}});}
class AnnotationInvocationHandler implements InvocationHandler, Serializable {private static final long serialVersionUID = 6182022883658399397L;// 保存了當(dāng)前注解的類型private final Class<? extends Annotation> type;// 保存了注解的成員屬性的名稱和值的映射,注解成員屬性的名稱實際上就對應(yīng)著接口中抽象方法的名稱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) {// 獲取當(dāng)前執(zhí)行的方法名稱String var4 = var2.getName();Class[] var5 = var2.getParameterTypes();if (var4.equals("equals") && var5.length == 1 && var5[0] == Object.class) {return this.equalsImpl(var3[0]);} else if (var5.length != 0) {throw new AssertionError("Too many parameters for an annotation method");} else {byte var7 = -1;switch(var4.hashCode()) {case -1776922004:if (var4.equals("toString")) {var7 = 0;}break;case 147696667:if (var4.equals("hashCode")) {var7 = 1;}break;case 1444986633:if (var4.equals("annotationType")) {var7 = 2;}}switch(var7) {case 0:return this.toStringImpl();case 1:return this.hashCodeImpl();case 2:return this.type;default:// 利用方法名稱從memberValues獲取成員屬性的賦值Object var6 = this.memberValues.get(var4);if (var6 == null) {throw new IncompleteAnnotationException(this.type, var4);} else if (var6 instanceof ExceptionProxy) {throw ((ExceptionProxy)var6).generateException();} else {// 這一步就是注解成員屬性返回值獲取的實際邏輯// 需要判斷是否是數(shù)組,如果是數(shù)組需要克隆一個數(shù)組// 不是數(shù)組直接返回if (var6.getClass().isArray() && Array.getLength(var6) != 0) {var6 = this.cloneArray(var6);}return var6;}}}}...}
通過 Java 系統(tǒng)屬性設(shè)置:
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");。通過 -D 參數(shù)指定,參數(shù)是:
-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true。
@RateLimit(value = 666)public class RateLimitMain {public static void main(String[] args) {System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");RateLimit rateLimit = RateLimitMain.class.getAnnotation(RateLimit.class);System.out.println(rateLimit.value());}}
public final class $Proxy1 extends Proxy implements RateLimit {private static Method m1;private static Method m2;private static Method m4;private static Method m0;private static Method m3;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 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 int value() throws {try {return (Integer)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("com.riemann.springbootdemo.annotation.RateLimit").getMethod("annotationType");m0 = Class.forName("java.lang.Object").getMethod("hashCode");m3 = Class.forName("com.riemann.springbootdemo.annotation.RateLimit").getMethod("value");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}}
歡迎大家關(guān)注我的公眾號【老周聊架構(gòu)】,Java后端主流技術(shù)棧的原理、源碼分析、架構(gòu)以及各種互聯(lián)網(wǎng)高并發(fā)、高性能、高可用的解決方案。
喜歡的話,點贊、再看、分享三連。

點個在看你最好看
評論
圖片
表情



