java注解的实现原理
使用
复制@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value();
}
Target 是 java 中的源注解,标识注解的使用位置,如类,方法,参数,变量等。
Retention 也是源注解,标识注解的作用范围,编译期,运行期。
复制@Log("hello")
public class User {
}
复制public class Client {
public static void main(String[] args) {
Log log = User.class.getAnnotation(Log.class);
System.out.println(log.value());
}
}
结果为
复制hello
原理
注解本质上是一个接口,
复制public interface Log
extends Annotation{
public abstract String value();
}
接下来我们跟一下 getAnnotation 方法的实现原理,
复制public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
// 关键就是 annotationData() 方法的实现
return (A) annotationData().annotations.get(annotationClass);
}
从类上获取注解对象
复制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
// 看一下 java 是如何创建注解的数据的
AnnotationData newAnnotationData = createAnnotationData(classRedefinedCount);
// try to install it
if (Atomic.casAnnotationData(this, annotationData, newAnnotationData)) {
// successfully installed new AnnotationData
return newAnnotationData;
}
}
}
Class 内部对注解数据是使用了缓存的,只会解析一次。
复制private AnnotationData createAnnotationData(int classRedefinedCount) {
// 这两个方法都是 native 方法
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);
}
IDE 在 debug 过程中,可以看到
declaredAnnotations 变量是一个 map,key 是注解接口的 class,value 是接口的一个动态代理实现,具体的处理是 AnnotationInvocationHandler,
package sun.reflect.annotation;
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") && 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;
}
}
<span class="hljs-keyword">switch</span>(var7) {
<span class="hljs-keyword">case</span> <span class="hljs-number">0</span>:
<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.toStringImpl();
<span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:
<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.hashCodeImpl();
<span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:
<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.type;
<span class="hljs-keyword">default</span>:
// 核心逻辑
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 {
if (var6.getClass().isArray()&& Array.getLength(var6) != 0) {
var6 = this.cloneArray(var6);
}
<span class="hljs-keyword">return</span> var6;
}
}
}
}
}
通过 debug 信息可以看到,注解的信息是保存在 AnnotationInvocationHandler 的 memberValues 变量中的,调用 value 方法是,会代理到 invoke 方法中,数据从 memberValues 变量中取。