注解是如何获取到的

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());
        }
    }

上一篇下一篇

猜你喜欢

热点阅读