美文网首页
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