美文网首页
注解是如何获取到的

注解是如何获取到的

作者: 我是光芒万丈 | 来源:发表于2022-05-24 22:41 被阅读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());
            }
        }
    
    

    相关文章

      网友评论

          本文标题:注解是如何获取到的

          本文链接:https://www.haomeiwen.com/subject/rkysprtx.html