注解是如何获取到的
2022-05-24 本文已影响0人
我是光芒万丈
注解是生效的呢?正常情况下示例如下:
定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Test {
public String getval();
}
使用
public class TestService implements ITestService {
@Test(getval = "su")
private String name;
@Override
public void sayHi() {
System.out.println(name);
}
}
那么但使用反射获取到类变量name上的注解对象,调用getval为什么就可以获取su这个值呢?
注解方法并无具体实现,答案就是动态代理。熟悉JDK代理的同学都知道,常见的jdk代理需要我们自行实现invocationhandler接口。
JDK代理常见用法:
interface Reader{
String getName();
}
public static void main(String[] args) {
Reader proxyReader = (Reader) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader() .getSystemClassLoader(), new Class[]{Reader.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行代理对象!");
return "test";
}
});
System.out.println(proxyReader.getName());
}
同理我们来看下invocation的子类,果然发现了AnnotationInvocationHandler
重点关注下它的invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) {
String member = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
// Handle Object and Annotation methods
if (member.equals("equals") && paramTypes.length == 1 &&
paramTypes[0] == Object.class)
return equalsImpl(args[0]);
if (paramTypes.length != 0)
throw new AssertionError("Too many parameters for an annotation method");
switch(member) {
case "toString":
return toStringImpl();
case "hashCode":
return hashCodeImpl();
case "annotationType":
return type;
}
//从memberValues中获取值并返回。
// Handle annotation member accessors
Object result = memberValues.get(member);
if (result == null)
throw new IncompleteAnnotationException(type, member);
if (result instanceof ExceptionProxy)
throw ((ExceptionProxy) result).generateException();
if (result.getClass().isArray() && Array.getLength(result) != 0)
result = cloneArray(result);
return result;
}
接下来,我们通过增加参数:
-Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true
保存相关代理类,来看下自定义方法getval实现,可以看到主要总是调用了我们实现的invocationHandler接口:
public final class $Proxy1 extends Proxy implements Test {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public $Proxy1(InvocationHandler var1) throws {
super(var1);
}
。。。
public final String getval() throws {
try {
return (String)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"));
m3 = Class.forName("com.Boyang.annotation.Test").getMethod("getval");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("com.Boyang.annotation.Test").getMethod("annotationType");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}