美文网首页
Retrofit中的注解反射与动态代理

Retrofit中的注解反射与动态代理

作者: Dalvik_ | 来源:发表于2021-08-12 15:35 被阅读0次

    1.注解的含义和应用场景

    注解的作用或者意义:
    单独的注解是一种注释,他需要结合其他如反射、插桩的等技术才有意义
    元注解:

    @Target    //作用目标,作用在什么地方
    
    ElementType.ANNOTATION_TYPE 可以应用于注解类型。
    ElementType.CONSTRUCTOR 可以应用于构造函数。
    ElementType.FIELD 可以应用于字段或属性。
    ElementType.LOCAL_VARIABLE 可以应用于局部变量。
    ElementType.METHOD 可以应用于方法级注解。
    ElementType.PACKAGE 可以应用于包声明。
    ElementType.PARAMETER 可以应用于方法的参数。
    ElementType.TYPE 可以应用于类的任何元素。
    
    @Retention  //保留时
    RetentionPolicy.SOURCE - 标记的注解仅保留在源级别中,并被编译器忽略。
    RetentionPolicy.CLASS - 标记的注解在编译时由编译器保留,但 Java 虚拟机(JVM)会忽略。
    RetentionPolicy.RUNTIME - 标记的注解由 JVM 保留,因此运行时环境可以使用它。
    
    @Retention 三个值中 SOURCE < CLASS < RUNTIME,即CLASS包含了SOURCE,RUNTIME包含SOURCE、
    CLASS。
    
    注解的不同级别应用场景
    • RUNTIME
      反射

    • SOURCE
      APT
      annotation processor tools 注解处理器
      apt 其实就可以看成javac的一个小插件
      APT 不会打包进入APK,只会在编译时参与编译

    • CLASS

    • 字节码插桩*
      在class中写代码
      java有语法检查,没有引用的类用不了,但是class已经经过了语法检查,所以随意 修改
      AOP 面向切面编程

    2.反射为什么慢?

    Java 反射效率低主要原因是:
    1.Method#invoke 方法会对参数做封装和解封操作

    • invoke 方法的参数是 Object[] 类型,也就是说,如果方法参数是简单类型的话,需要在此转化成 Object 类型,例如 long ,在 javac compile 的时候 用了Long.valueOf() 转型,也就大量了生成了Long 的 Object, 同时 传入的参数是Object[] 数值,那还需要额外封装 object 数组。而在 MethodAccessorGenerator#emitInvoke 方法里我们看到,生成的字节码时,会把参数数组拆解开来,把参数恢复到没有被 Object[] 包装前的样子,同时还要对参数做校验,这里就涉及到了解封操作。因此,在反射调用的时候,因为封装和解封,产生了额外的不必要的内存浪费,当调用次数达到一定量的时候,还会导致 GC

    2.需要检查方法可见性

    • 反射时每次调用都必须检查方法的可见性(在 Method.invoke 里)

    3.需要校验参数

    • 反射时也必须检查每个实际参数与形式参数的类型匹配性(在NativeMethodAccessorImpl.invoke0 里或者生成的 Java 版 MethodAccessor.invoke 里)

    4.反射方法难以内联

    • Method#invoke 就像是个独木桥一样,各处的反射调用都要挤过去,在调用点上收集到的类型信息就会很乱,影响内联程序的判断,使得 Method.invoke() 自身难以被内联到调用方

    5.JIT 无法优化

    Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.""

    • 因为反射涉及到动态加载的类型,所以无法进行优化。
      2.Java动态代理原理
     Object o = Proxy.newProxyInstance(this.getClassLoader(), this.getClass().getInterfaces(),
                    new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    return null;
                }
            });
    

    动态代理的参数函数
    类加载器
    要代理的接口
    回调

    3.Retrofit中的实践

    create中 动态代理获取对象,获取所有的方法注解,参数注解以及所有参数

    相关文章

      网友评论

          本文标题:Retrofit中的注解反射与动态代理

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