Retrofit是如何工作的?(源码分析)

这里直接介绍Retrofit的原理,如果你还不是很熟悉retrofit的使用,可以看笔者对retrofit之前写过的详细介绍查看传送门

1.Retrofit中的create()方法分析

  public <T> T create(final Class<T> service) {
    //....
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            //....
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }
  • 通过以上代码核心方法:loadServiceMethod
   ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
  • 那么可以分析loadServiceMethod(method)做了什么事?根据method参数,构造一个ServiceMethod对象,那么ServiceMethod是什么东西,又为我们做了什么事?
ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

2. 接下来再看看ServiceMethod中是什么东西?为什么将处理的方法都封装为ServiceMethod

  • 以下是源码:
final class ServiceMethod<R, T> {
  
  final okhttp3.Call.Factory callFactory;
  final CallAdapter<R, T> callAdapter;

  private final HttpUrl baseUrl;
  private final Converter<ResponseBody, R> responseConverter;
  private final String httpMethod;
  private final String relativeUrl;
  private final Headers headers;
  private final MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;

  ServiceMethod(Builder<R, T> builder) {
    this.callFactory = builder.retrofit.callFactory();
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl();
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod;
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;
  }
  //...
}
  • ServiceMethod中大致有以下成员变量及说明:
    CallAdapter //这里会根据平台信息,返回Default或者说自定义的,比如RxJava2CallAdapter
    Converter //如GsonConvertAdapter,将okhttp的response转为json的处理adapter
    Okhhtp3.Call.Factory 即配置的OkhttpClient
    method //方法名
    Annotation[] methodAnnotations //方法注解
    Annotation[][] parameterAnnotationsArray //方法参数

ServiceMethod中保存了Http请求的所有的参数和当前方法需要调度的Call和Convert
方法
使用Map将method于ServiceMethod用于缓存,提高全局访问的性能

3.开始创建OKHttpCall

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

当封装完method转化为ServiceMethod后,执行上面这句,则创建出OkhttpCall对象,即将ServiceMehod中封装的信息和参数,准备好这些资源以后,则全部交个OkhttpCall,从 OkHttpCall 这个名字来看就能猜到,它是对 OkHttp3.Call 的组合包装,事实上,它也确实是。(OkHttpCall中有一个成员okhttp3.Call rawCall)。当然跟进去发现了如下代码,是不是很熟悉?,显然这是okhttp请求网络的流程的真正开始的地方。可以看笔者之前对okhttp源码分析的一系列文章传送门

    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);

封装为Okhttp所需要的request对象,然后newCall创建一个

RealCall.newRealCall(this, request, false /* for web socket */);

则开始执行一个okhttp请求方法,至于okhttp如何网络请求,这里请参看笔者之前写的okhttp的源码的分析,这里不做过多的研究,

4.执行CallAdapter

当执行Call.enqueue()方法后,或者说如果结合Rxjava进行订阅了以后,则调用Okhttp的enqueue()方法,通过createCall()方法,得到OkhttpClient中返回的Response,然后根据之前在ServiceMethod中封装的ConverAdapter方法,将Response进行

 response = parseResponse(rawResponse);

parseResponse核心方法

T body = serviceMethod.toResponse(catchingBody);

5. 执行convertAdapter

responseConverter.convert(body)

因为在初始化Retrofit的时候设置了ConverterFactory为

Retrofit.create(ApiService.class)
...
.addConverterFactory(GsonConverterFactory.create())
...

则使用GsonConverterFactory处理catchingBody,这里在看看GsonConverterFactory的方法

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      return adapter.read(jsonReader);
    } finally {
      value.close();
    }
  }
}

到这里,retrofit的请求网络的大体流程则完成

总结

Retrofit 使用了动态代理给将我们定义的接口设置了代理,当调用接口的方法时,Retrofit 会拦截下来,然后经过一系列处理,比如解析方法的注解和参数,生成了 Call 、Request 、等OKHttp所需的资源,最后交给 OkHttp 去发送请求, 此间经过 callAdapter,convertr 的处理。

在callAdapter处理的过程中,会将okhttp中的call,转化为Observable(自定义设定的,即使没有,也会根据平台创建一个默认的),最终执行call.execute(),开始真正的请求

将请求得到的结果通过convertAdapter处理后,转化为定义的返回类型,然后根据处理结果进行回调

即:Retrofit 中的数据其实是交给了 callAdapter 以及 converter 去处理,callAdapter 负责把 okHttpCall 转成我们所需的 Observable类型,converter负责把服务器返回的数据转成具体的实体类。

    原文作者:OneXzgj
    原文地址: https://www.jianshu.com/p/62920e404700
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞