美文网首页
Retrofit2 源码分析

Retrofit2 源码分析

作者: 菜鸟汤先生 | 来源:发表于2016-09-29 15:57 被阅读0次

    将一个Java接口翻译成一个Http请求,然后用OkHttp去发送这个请求

    一 入口类 Retrofit   成员变量

    private final  HttpUrl baseUrl;//网络请求基地址

    private final List<Converter.Factory>converterFactories;//数据转换器工厂集合

    private final List<CallAdapter.Factory> adapterFactories;//网络请求适配器工厂集合

    private final okhttp3.Call.Factory callFactory;//底层进行网络请求工厂

    private final Executor callbackExecutor;//回调方法执行器

    /ServiceMethod是对业务接口中方法的注解进行解析之后得到的对象,该对象包含了访问网络的除了方法参数值之外的所有必要信息;如数据转换器、网络请求适配器、网络请求工厂、基地址、Http方法等等。

    private final Map<Method,ServiceMethod> serviceMethodCache =newLinkedHashMap<>();

    Retrofit.bulid()方法 初始化 外观模式

    二 动态代理

    https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/ 动态代理的机制

    http://www.ibm.com/developerworks/cn/java/j-jtp08305.html 动态代理的Decorator

    GitHubServiceservice = retrofit.create(GitHubService.class);

    create方法就是返回了一个Proxy.newProxyInstance动态代理对象

    动态代理是java中的字节码生成技术。通过接口生成代理类,并将代理类的实现交给InvocationHandler作为具体的实现 ,

    动态代理作为 Decorator 

    就是你要调用某个class方法的前后 ,你可以很方便的插入些你想要执行的额外代码

    一个动态代理类可以充当所有接口的 Decorator 或 Proxy,这样就不用每个接口都编写一个具体的实现类

    Call <List<Repo>> repos = service.listRepos("octocat");

    执行流程:

    service对象其实是一个动态代理对象,并不是一个真正的GitHubService接口的implements产生的对象,当api对象调用listRepos方法时会被动态代理拦截,然后调用Proxy.newProxyInstance方法中的InvocationHandler对象的invoke方法。

    invoke方法会传入3个参数:

    Object proxy, 代理对象

    Method method,调用的方法 listRepos

    Object... args 方法参数 octocat

    Retrofit里的动态代理比较巧妙。它不关心proxyd,只是单纯的为了拿到了这个method上所有的注解 生成ServiceMethod对象,生成的ServiceMethod对象和args构造生成了HttpCall  可以发起HTTP请求的类

    总结:简化复杂的网络请求,通过动态代理的去处理解析与拼装HTTP请求

    三 核心类 ServiceMethod

    一个ServiceMethod对象对应于一个 API interface 的一个方法

    主要成员变量

    final okhttp3.Call.Factory callFactory; //负责创建 HTTP 请求

    final CallAdapter callAdapter; //请求适配器  把retrofit2.Call<T>转为T

    private final Converter responseConverter;  负责把服务器返回的数据(JSON、XML、二进制或者其他格式,由ResponseBody封装)转化为T类型的对象

    private final Headers headers; //请求头信息

    private final ParameterHandler[ ] parameterHandlers;//负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数

    初始化过程 build()方法

    callAdapter= createCallAdapter();//将遍历一个CallAdapter.Factory列表,根据方法返回值类型和注解提供需要的网络请求适配器

    responseType=callAdapter.responseType();

    responseConverter= createResponseConverter();//;即根据方法返回值类型和注释从retrofit中获取对应的转换器

    for(Annotation annotation :methodAnnotations) {

    parseMethodAnnotation(annotation);//解析Method的注解 给ServiceMethod的成员变量赋值

    }

    for(intp =0;p < parameterCount;p++) {

    ...

    parameterHandlers[p] = parseParameter(p,parameterType,parameterAnnotations);

    //方法中的每个参数创建一个ParameterHandler对象,该对象的创建过程就对方法参数中的Body、PartMap、Part、FieldMap、Field等注解进行解析

    }

    核心:okhttp3.Call.Factory,CallAdapter.Factory和Converter.Factory三个工厂类,模块之间、类之间通过接口进行依赖,创建十么样的实现类交给工厂去处理,工厂同样也是接口,添加怎样的工厂,则在最初构造Retrofit对象时决定,各个模块之间完全解耦,每个模块只负责自己的责任

    四 执行HTTP请求

    4.1 OkHttpCall类中execute() 同步发起网络请求,执行分析

    createRawCall()    

    1调用了serviceMethod.toRequest(args)来创建okhttp3.Request对象,之前解析参数注解的parameterHandlers在这里给HTTP请求 设置参数传进入,最后RequestBuilder build()生成Request请求

    2 再调用serviceMethod.callFactory.newCall(request)来创建okhttp3.Call,这里之前准备好的callFactory同样也派上了用场,由于工厂在构造Retrofit对象时可以指定,所以我们也可以指定其他的工厂,来使用其它的底层 HttpClient 实现。这里Retrofit2就和Okhttp结合起来了 网络请求的执行业务流程都交给Okhttp来处理

    return parseResponse(call.execute());

    调用okhttp3.Call#execute()来执行网络请求,这个方法是阻塞的,执行完毕之后将返回收到的响应数据。收到响应数据之后,进行状态码的检查,再调用serviceMethod.toResponse(catchingBody)来把响应数据转化成我们需要的数据类型对象。使用之前准备好的responseConverte转化数据。

    4.2 enqueue(Callback callback) 异步执行

    这里的异步交给了okhttp3.Call#enqueue(Callback responseCallback)来实现,并在它的 callback 中调用parseResponse解析响应数据,并转发给传入的 callback

    五  CallAdapter 接口

    请求的适配化OkHttpCall --Adapter--> RxJava/java8/UICallback

    通过适配器实现OkHttpCall到其它类型(比如RxJava等第三方库)的适配转换

    public Interface CallAdapter<T> {

    Type responseType();//该请求适配器返回的数据类型

     T adapt(Call call);//该请求适配器对原始Call的再次封装,如Call到Observable,

    abstract class  Factory {

    public abstract CallAdapter get(Type returnType, Annotation[] annotations, Retrofit retrofit);//获取网络请求适配器

    protected    staticType getParameterUpperBound(intindex, ParameterizedType type) 

    {returnUtils.getParameterUpperBound(index, type); }

    protectedstaticClass getRawType(Type type) {returnUtils.getRawType(type); }

    }

    ExecutorCallAdapterFactory 是Retrofit默认实现  

    该对象存储一个回调执行器,异步请求将相应的结果交给callbackExecutor回调执行器去执行Android平台Retrofit2会使用主线程handler构造一个ExecutorCallAdapterFactory,调用enqueue(Callback),callback回调会在主线程中回调

    5.1 Retrofit2和RxJava的结合使用

    1 RxJavaCallAdapterFactory类 

     RxJava对请求进行包装,它将根据网络请求生成一个Observable进行流式任务执行

    getCallAdapter方法中对返回值的泛型类型进行了进一步检查,例如我们声明的返回值类型为Observable,泛型类型就是List,这里对retrofit2.Response和retrofit2.adapter.rxjava.Result进行了特殊处理,有单独的 adapter 负责进行转换,其他所有类型都由SimpleCallAdapter负责转换

    2 SimpleCallAdapter#adapt方法

    创建了一个Observable,传入了CallOnSubscribe类,同时使用了一个OperatorMapResponseToBodyOrError操作符,用来把retrofit2.Response转为我们声明的类型,或者错误异常类型

    3 CallOnSubscribe#call方法

    clone 了原来的 call,因为okhttp3.Call是只能用一次的,所以每次都是新 clone 一个进行网络请求;创建了一个叫RequestArbiter的 producer,把这个 producer 设置给 subscriber;

    Producer机制 简单的理解

    Subscriber 都是被动接收 Observable 传递 过来的数据,然后Subscriber做处理。

    但要是 Observable 发得太多,Subscriber 处理不过来,那就有问题了,所以就有了一种 Subscriber 主动 pull 的机制,而这种机制就是通过 Producer 实现的。给 Subscriber 设置 Producer 之后(通过Subscriber#setProducer方法),Subscriber 就会通过 Producer 向上游根据自己的能力请求数据(通过Producer#request方法),而 Observable 收到请求之后再根据请求的量给 Subscriber 发数据。

    RequestArbiter#request方法

    执行call.execute() 获取到Response响应数据,并且发送给下游接收

    Observable.lift(OperatorMapResponseToBodyOrError.instance())

    lift操作符 负责接收原始的Observable发出的事件,并在response.body()并发送给下游。这里,body()返回的就是我们声明的泛型类型了

    Call<R>->Response<T>->Observable<T>  执行流程

    1 Observable.subscribe,触发 API 调用的执行;

    2 CallOnSubscribe#call,clone call,创建并设置 producer;

    3 subscriber 被设置了 producer 之后调用RequestArbiter#request,在 request 中发起网络请求,把处理结果发给下游;

    4 OperatorMapResponseToBodyOrError$1#onNext,把 response 的  body 发给下游

    5 最终就到了我们 subscribe 时传入的回调里面了;

    六    概括Retrofit2的话,借鉴了服务器编程中AOP思想,利用动态代理技术通过接口在运行时拦截方法,接着通过解析注解拼装HTTP请求;最后包装了OkHttpCall生成真正的请求类 发起网络请求, 通过抽象工厂让各个模块直接解耦,完成对原数据Respone的Conver,实现了对Rx、线程的Adapter ,

    相关文章

      网友评论

          本文标题:Retrofit2 源码分析

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