Retrofit源码分析(超详细)

Retrofit是对OKHttp的封装,简化了网络请求。具体使用参见官方文档。本文从一次完整的同步请求分析源码,跟着源码一起阅读,肯定会有收获的。分析的版本是retrofit-2.1.0

支持原创,转载请注明出处。

老规矩,先上图。

类图

Retrofit.png

实例

public class LearnRetrofit {
    public static final String API_URL = "https://api.github.com";

      //创建接口
      public interface GitHub {
        @GET("/repos/{owner}/{repo}/contributors")
        Call<ResponseBody> contributors(
            @Path("owner") String owner,
            @Path("repo") String repo);
      }

      public static void main(String[] args) throws IOException {
        //创建Retrofit对象
        Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(API_URL)
            .build();

        //动态生成一个代理对象
        GitHub github = retrofit.create(GitHub.class);

        //生成一个OKHttpCall的代理对象
        Call<ResponseBody> call = github.contributors("square", "retrofit");

        //返回结果
        Response<ResponseBody> response = call.execute();
        
        //打印数据
        System.out.println(response.body().string());
      }
}

我们从官方文档里的一个例子开始。我做了一些修改,开始不使用GsonConverter对结果进行转换,后面会添加,在默认情况下Retrofit只支持将HTTP的响应体转换换为ResponseBody(OKHttp中的类),默认情况下Retrofit使用BuiltInConverters这个默认的Converter,后面会再次提到。第一步,创建一个接口。第二步,创建一个Retrofit对象,提供BASE_URL等信息。第三步,创建一个实现了接口的代理对象。第四步,调用接口方法,返回一个Call对象。第五步,调用execute执行同步请求。第六步,从响应获取数据。我们跟着步骤一步一步分析。

创建Call

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //Proxy.newProxyInstance()返回一个Github的代理类对象
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          //这个invoke方法会在代理对象的方法中调用,第一个参数就是代理对象
          //第二个参数是代理对象调用的方法
          //第三个参数方法的参数
          @Override public Object invoke(Object proxy, Method method, Object... args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
           //调用loadMethodHandler
            return loadMethodHandler(method).invoke(args);
          }
        });
  }

这里使用了动态代理,Proxy.newProxyInstance()返回一个Github的代理类对象。当我们调用github这个代理对象的方法比如contributors()时,会调用调用上述的invoke方法,第一个参数就是代理对象,第二个参数是代理对象调用的方法,第三个参数是方法的参数。动态代理可以看我以前的写的文章,建议完全搞懂动态代理,然后往下看。假设现在我调用了github.contributors("square", "retrofit")那么会调用invoke方法,然后调用loadMethodHandler()方法。

  MethodHandler loadMethodHandler(Method method) {
    MethodHandler handler;
    synchronized (methodHandlerCache) {
      handler = methodHandlerCache.get(method);
      if (handler == null) {
        //创建MethodHandler 对象
        handler = MethodHandler.create(this, method);
        methodHandlerCache.put(method, handler);
      }
    }
    return handler;
  }

loadMethodHandler()返回一个MethodHandler对象,然后调用这个对象的invoke()方法。我们看下这个类。

//核心成员变量
  private final okhttp3.Call.Factory callFactory;
  private final RequestFactory requestFactory;
  private final CallAdapter<?> callAdapter;
  private final Converter<ResponseBody, ?> responseConverter;

//核心方法
  static MethodHandler create(Retrofit retrofit, Method method) {
    //创建CallAdapter
    CallAdapter<?> callAdapter = createCallAdapter(method, retrofit);
    Type responseType = callAdapter.responseType();
    if (responseType == Response.class || responseType == okhttp3.Response.class) {
      throw Utils.methodError(method, "'"
          + Types.getRawType(responseType).getName()
          + "' is not a valid response body type. Did you mean ResponseBody?");
    }
   //创建Converter
    Converter<ResponseBody, ?> responseConverter =
        createResponseConverter(method, retrofit, responseType);
    RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit);
    return new MethodHandler(retrofit.callFactory(), requestFactory, callAdapter,
        responseConverter);
  }

//创建CallAdapter
  private static CallAdapter<?> createCallAdapter(Method method, Retrofit retrofit) {
    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw Utils.methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
      throw Utils.methodError(method, "Service methods cannot return void.");
    }
    Annotation[] annotations = method.getAnnotations();
    try {
      //调用Retrofit.callAdapter()
      return retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw Utils.methodError(e, method, "Unable to create call adapter for %s", returnType);
    }
  }

//创建Converter
  private static Converter<ResponseBody, ?> createResponseConverter(Method method,
      Retrofit retrofit, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
    try {
      //调用Retrofit.responseBodyConverter()方法
      return retrofit.responseBodyConverter(responseType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw Utils.methodError(e, method, "Unable to create converter for %s", responseType);
    }
  }

在创建MethodHandler这个类的时候,我要创建一个CallAdapter和一个Converter,从流程看,分别调用retrofit.callAdapter(returnType, annotations);retrofit.responseBodyConverter(responseType, annotations);创建。Retrofit的这两个方法最终调用如下两个方法。

  public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      //从adapterFactories这个LIst获取
      CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

    StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
        .append(returnType)
        .append(".\n");
    if (skipPast != null) {
      builder.append("  Skipped:");
      for (int i = 0; i < start; i++) {
        builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
      }
      builder.append('\n');
    }
    builder.append("  Tried:");
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
  }



  public <T> Converter<T, RequestBody> nextRequestBodyConverter(Converter.Factory skipPast,
      Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {
    checkNotNull(type, "type == null");
    checkNotNull(parameterAnnotations, "parameterAnnotations == null");
    checkNotNull(methodAnnotations, "methodAnnotations == null");

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      //从converterFactories这个List获取
      Converter.Factory factory = converterFactories.get(i);
      Converter<?, RequestBody> converter =
          factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<T, RequestBody>) converter;
      }
    }

    StringBuilder builder = new StringBuilder("Could not locate RequestBody converter for ")
        .append(type)
        .append(".\n");
    if (skipPast != null) {
      builder.append("  Skipped:");
      for (int i = 0; i < start; i++) {
        builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
      }
      builder.append('\n');
    }
    builder.append("  Tried:");
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
  }

这两个方法分别从adapterFactories和converterFactories获取一个CallAdapter和Converter,我们看下这两个List是如何构造的。

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      // 创建List保存CallAdapter.Factory
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      //添加一个默认的CallAdapterFactory
    adapterFactories.add(Platform.get().defaultCallAdapterFactory(callbackExecutor));

      // 创建List保存Converter.Factory
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }


    public Builder() {
      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
     //添加默认的ConverterFactory
      converterFactories.add(new BuiltInConverters());
    }

如果我们在构造Retrofit时没有提供CallAdaCallAdapter.Factory和Converter.Factory,构造时会使用默认值,我看看下代码

//添加默认CallAdapterFactory
adapterFactories.add(Platform.get().defaultCallAdapterFactory(callbackExecutor));   

//最终是这个类
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();

  @Override
  public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }

    final Type responseType = Utils.getCallResponseType(returnType);
    //返回匿名CallAdapter类
    return new CallAdapter<Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public <R> Call<R> adapt(Call<R> call) {
        return call;
      }
    };
  }
}

我们看到DefaultCallAdapterFactory生成的匿名CallAdapter类的adapt方法把call原封不动得传回。再来看看RequestBodyConverter。

  static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
    static final RequestBodyConverter INSTANCE = new RequestBodyConverter();
    
     //将RequestBody原封不动返回,不做任何处理
    @Override public RequestBody convert(RequestBody value) throws IOException {
      return value;
    }
  }

好了,到这里我们总结下,我们创建了一个MethodHandler对象,创建过程中,我们又创建了一个默认的CallAdapter和一个默认的RequestBodyConverter 。创建完了MethodHandler,我们调用了它的invoke()方法。

  Object invoke(Object... args) {
    return callAdapter.adapt(
        new OkHttpCall<>(callFactory, requestFactory, args, responseConverter));
  }

这里使用了我们刚才创建的默认的CallAdapter,上面我们知道它的adapt()仅仅是返回参数,其他什么都不做。所以这里返回的是一个OkHttpCall对象。这个OkHttpCall实现了Call<T>接口。我们总结下,到现在为止,我们仅仅调用了这两句

//动态生成一个代理对象
GitHub github = retrofit.create(GitHub.class);

//生成一个OKHttpCall的代理对象
Call<ResponseBody> call = github.contributors("square", "retrofit");

所以我们知道Call<ResponseBody> call = github.contributors("square", "retrofit")返回的就是OkHttpCall对象。接下来我们应该调用Response<ResponseBody> response = call.execute();,我们看下OkHttpCall的execute方法。

调用call.execute()

final class OkHttpCall<T> implements Call<T> {
//核心成员变量
  private final okhttp3.Call.Factory callFactory;
  private final RequestFactory requestFactory;
  private final Object[] args;
  private final Converter<ResponseBody, T> responseConverter;

//核心方法
  @Override public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      if (creationFailure != null) {
        if (creationFailure instanceof IOException) {
          throw (IOException) creationFailure;
        } else {
          throw (RuntimeException) creationFailure;
        }
      }

      call = rawCall;
      if (call == null) {
        try {
           //将任务抛给OKHttp
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException e) {
          creationFailure = e;
          throw e;
        }
      }
    }

    if (canceled) {
      call.cancel();
    }
   
    //转换结果
    return parseResponse(call.execute());
  }

 //生成okhttp3.Call
  private okhttp3.Call createRawCall() throws IOException {
    //这个callFactory就是OKHttpClient
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

 //将okhttp3.Response转换成Response
  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();

    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
      try {
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }

    if (code == 204 || code == 205) {
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      //这个responseconverter就是默认提供的RequestBodyConverter,当然我们可以替换成自己的converter比如GsonConverter
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }

好了,再次总结下,我们调用了OKHttpCall.execute(),该方法生成一个okhttp3.Call将任务抛给OKHttp,完了调用parseResponse,用Converter将okhttp3.Response转换成我们在范型中指定的类型Response<ResponseBody> response = call.execute(),我指定了okhttp3.ResonseBody。然后返回结果。如果我在构造Retrofit时提供了GsonConverter,addConverterFactory(GsonConverterFactory.create())那么上面的T body = responseConverter.convert(catchingBody);responseConverter就是GsonConverter。

总结

Retrofit就是对OkHttp的包装,了解原理后我们将更好地使用它。

如果觉得写得还不错可以关注我哦,后面会将更多笔记的内容整理成博客。
支持原创,转载请注明出处。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容