都知道Retrofit是通过动态代理来生成代理对象作为网络请求的发起者。

今天就来看下动态代理是怎么操作的。或者说是怎么让一个貌似接口的对象调用它的抽象方法呢?

先来看代码

public static void main(String[] args) {Factory factory = new Factory();Bird bird = factory.create(Bird.class);bird.fly();
}interface Bird {void fly();
}复制代码

这里代码通过一个Factory 实例调用create方法,传入一个接口的class对象就可以返回一个接口的实例,可以调用接口中的方法fly()

而在我们的静态代码中并没有一个类去实现了这个Bird接口(完整代码可以看下方)。那么这个对象到底是从哪里来的呢?

完整代码如下

public class DynamicProxy {interface Bird {void fly();}public static void main(String[] args) {Factory factory = new Factory();Bird bird = factory.create(Bird.class);bird.fly();}static class Factory implements InvocationHandler {public <T> T create(Class<T> target) {return (T) Proxy.newProxyInstance(target.getClassLoader(),new Class[]{target},this);}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("flying...");return null;}}
}
复制代码

在调用bird.fly()时,输出结果为flying...,很明显,代码中就如同开始所说的,并不存在一个实现了Bird接口的子类,而bird又实实在在调用了fly()方法。唯一的可能就是bird是接口的实例(或者说实现接口的子类的对象)。这里看起来似乎就有些诡异了。

当然编程没有魔法,这里只是利用到了Java的动态代理,通过Proxy.newProxyInstance()方法生成实现了指定接口的子类,然后返回了这个动态生成类的实例对象。

这个子类在调用接口中的方法时,其实调用的是InvocationHandlerinvoke()方法。在此方法中会有对应参数的回调,可以根据这些参数做出合适的拦截/增强等操作。

要留意的一点是JDK提供的动态代理,动态生成的子类是继承自Proxy类的,,而Java是不支持多继承的,所以很显然。通过动态代理返回的对象必然是以接口形式来接收的,扩展的只有接口和实现接口的子类,对于一些没有实现接口的类是没有办法进行扩展的。(cglib支持扩展类)

知道了这些也就明白了Retrofit的动态代理大致是个什么逻辑。

下面仿造Retrofit通过方法上注解来模拟一次网络请求吧。

通过在接口中在方法上的注解,确定一些请求的参数。然后创建代理对象,在方法中拼接处完整的Url, https://github.com/search?q=java

请求网络,并且在响应头中的Status字段打印出来。

public interface Bird {@Protocol()@Method()@Path("search")@Query("q=java")@Url("github.com")String fly();
}public class Test {public static void main(String[] args) {Factory factory = new Factory();Bird bird = factory.create(Bird.class);String status = bird.fly();System.out.println(status);//输出 Status: 200 OK}
}
复制代码

部分代码

public class Factory implements InvocationHandler {OkHttpClient httpClient = new OkHttpClient();public <T> T create(Class<T> target) {return (T) Proxy.newProxyInstance(target.getClassLoader(),new Class[]{target},this);}public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable {String get = method.getAnnotation(Method.class).method();String protocol = method.getAnnotation(Protocol.class).value();String url = method.getAnnotation(Url.class).value();String path = method.getAnnotation(Path.class).value();String query = method.getAnnotation(Query.class).value();String entire_url = protocol + "://" + url + "/" + path + "?" + query;System.out.println(entire_url);Request build = new Request.Builder().url(entire_url).get().build();return httpClient.newCall(build).execute().headers().get("Status");}
}
复制代码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Method {String method() default "GET";
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Url {String value();
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Protocol {String value() default "https";
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Path {String value();
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Query {String value() default "";
}复制代码

转载于:https://juejin.im/post/5a31ee51f265da430e4f2bea

Retrofit的动态代理相关推荐

  1. [动态代理三部曲:下] - 从动态代理,看Retrofit的源码实现

    前言 关于动态代理的系列文章,到此便进入了最后的"一出好戏".前俩篇内容分别展开了:从源码上,了解JDK实现动态代理的原理:以及从动态代理切入,学会看class文件结构的含义. 如 ...

  2. Retrofit2 源码解析之动态代理

    基于 Retrofit 2.3.0 & Android 8.1 分析 Java 动态代理在 Android 上的实现 未经允许不得转载 Retrofit 使用示例 public interfa ...

  3. [动态代理三部曲:上] - 动态代理是如何坑掉了我4500块钱

    前言 不知道,起这个名字算不算是标题党呢?不过如果小伙伴们可以耐心看下去,因为会觉得不算标题党~ 这是一个系列文章,目的在于通过动态代理这个很基础的技术,进而深入挖掘诸如:动态生成class:Clas ...

  4. java 获取动态的service_【Android】动态代理在 Retrofit 中的使用

    首先,什么是动态代理和为什么会有动态代理. 众所周知,Java 是一门静态语言,编写完的类,无法在运行时做动态修改. 一个简单的动态代理如下: 1.先定义一个接口,想要使用动态代理,必须先定义一个接口 ...

  5. Android代理模式(静态代理,动态代理,Retrofit代理模式分析)

    文章目录 代理模式 前言:AOP编程(面向切面编程) 一. 代理思想 1. 静态代理 2. 动态代理 3. 动态代理的实现 二. Retrofit代理模式分析 代理模式 前言:AOP编程(面向切面编程 ...

  6. Android开发中无处不在的设计模式——动态代理模式

    继续更新设计模式系列.写这个模式的主要原因是近期看到了动态代理的代码. 先来回想一下前5个模式: - Android开发中无处不在的设计模式--单例模式 - Android开发中无处不在的设计模式-- ...

  7. android中多态的应用_动态代理原理及在 Android 中的应用

    code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者:trampcr 链接:https://www.jianshu.com/p/492903ab2fae 声明:本文已 ...

  8. 动态代理[JDK]机制解析

    代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 动态代理是一种比较常用的代理 ...

  9. Android APP热更新中的插件化(Hook技术:反射或动态代理),Demo (2)

    修改AAPT,资源分区,用于Android插件化- https://github.com/BaoBaoJianqiang/AAPT -- Android下的挂钩(hook)和代码注入(inject) ...

最新文章

  1. 题目 1083:【蓝桥杯】【入门题】Hello, world!
  2. reactor官方文档译文(2)Reactor-core模块
  3. InfoWorld的日志管理系统评测
  4. leetcode 501. 二叉搜索树中的众数(Java版)
  5. 关于ECMAScript6 的学习01-ES6 的六种变量声明方式===关于常量const
  6. OpenShift 之 Quarkus(1)创建第一个Quarkus应用
  7. Linux离线同步时间
  8. 谈谈现在软件测试行业的趋势和面试必备的东西
  9. watch the fixed address in qt
  10. win10+cuda10+tensorflow-gpu最新安装教程
  11. php webshell 过狗
  12. python sqrt(4)*sqrt(9),Python sqrt() 函数
  13. 数字化给财税行业带来的星星之火
  14. python程序设计心得体会感想-如何快速学会Python
  15. Docker buil提示https://registry-1.docker.io/v2/: read tcp 10.221->:443: read: connection reset by peer
  16. 先试后买!解析购物新体验背后的移动AI+AR技术
  17. 【操作系统】第2章 进程与线程
  18. 技术状态管理(六)-技术状态审核
  19. oracle 菜单不见了,开始菜单不见了怎么办 开始菜单不见了解决方法【详解】
  20. java 如何建立servlet_Servlet怎么新建

热门文章

  1. 常见硬件术语大全(上)
  2. 数据库高可用架构(MySQL、Oracle、MongoDB、Redis)
  3. ●洛谷P3168 [CQOI2015]任务查询系统
  4. [codevs1022]覆盖
  5. codevs 1227 方格取数 2
  6. [LeetCode]Gray Code
  7. Ubuntu 11.10 开机让 Varnish 跟随 Nginx 一起启动
  8. [转]Visual Assist X设置
  9. 如何向列表中添加数据值(管理员篇)
  10. NameError: name 'go' is not defined