Retrofit2源码分析

本文将顺着构建请求对象->构建请求接口->发起同步/异步请求的流程,分析Retrofit是如何实现的。

开始之前,我们先看下Retrofit的基本使用方式

Step1:

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

Step2:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create()) // json response
    .build();

GitHubService service = retrofit.create(GitHubService.class);

Step3:

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

// async(异步方式)
repos.enqueue(new Callback<List<Repo>>() {
    @Override
    public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
        if (response.isSuccessful()) { // successful response
            List<Repo> repos = response.body(); // converted response
        }
    }

    @Override
    public void onFailure(Call<List<Repo>> call, Throwable t) {}
});

通过以上三步,可以将服务器返回的json格式数据,转换为List<Repo>。

是不是非常的简单和清晰?我们似乎只写了一个GitHubService接口,定义了一个listRepos方法并加了一些注解,然后使用Retrofitcreate方法拿到GitHubService实例service,再调用listRepos方法就拿到了我们想要的数据。

好奇心驱使我弄明白这一切的来龙去脉~

构建Retrofit
Step2 我们可以看出来Retrofit使用了建造者模式来创建,Retrofit有几个重要的属性

public final class Retrofit {
  // ServiceMethod缓存,ServiceMethod其实是封装了调用listRepos时,请求的所有信息(请求方法GET、请求参数名称和值、请求地址等)
  private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();

  // 发起网络请求库
  private final okhttp3.Call.Factory callFactory; // 默认是OkHttpClient
  private final HttpUrl baseUrl; // 请求地址,不能为空
  private final List<Converter.Factory> converterFactories; // 转换器的工厂集合
  private final List<CallAdapter.Factory> adapterFactories; // 将返回结果包装成默认的Call<?>或者RxJava的Observable(默认内置ExecutorCallAdapterFactory)
  private final Executor callbackExecutor; // 负责控制回调结果所在的线程,Android默认是在主线程(MainThreadExecutor)
  ...
}

以上这些属性会在Retrofit.Builder的build方法中去设置,其中会有些默认的属性

public static final class Builder {
  // ...
  Builder(Platform platform) {
    this.platform = platform;
    // Add the built-in converter factory first. This prevents overriding its behavior but also
    // ensures correct behavior when using converters that consume all types.
    converterFactories.add(new BuiltInConverters());
  }
  // ...
  public Retrofit build() {
    if (baseUrl == null) {
      throw new IllegalStateException("Base URL required.");
    }

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

    Executor callbackExecutor = this.callbackExecutor;
    if (callbackExecutor == null) {
      callbackExecutor = platform.defaultCallbackExecutor();
    }

    // Make a defensive copy of the adapters and add the default Call adapter.
    List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
    adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

    // Make a defensive copy of the converters.
    List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

    return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
      callbackExecutor, validateEagerly);
  }
}
  1. baseUrl如果为空会抛出异常“Base URL required”,所以这个参数不能为空。

  2. callFactory如果不指定,则使用默认的OkHttpClient来作为网络库。

  3. callbackExecutor如果为空,会根据不同平台Platform来设置,Android默认用的是下面这个MainThreadExecutor。它的作用就是线程调度器,会控制最终回调结果所在的线程。

  4. adapterFactories首先会添加我们自定义的适配器工厂,然后会加上系统内置的ExecutorCallAdapterFactory。这与第三点是一致的,都是根据不同平台来设置,Android平台如下:

    static class Android extends Platform {
     @Override public Executor defaultCallbackExecutor() {
       return new MainThreadExecutor();
     }
    
     @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
       return new ExecutorCallAdapterFactory(callbackExecutor);
     }
    
     static class MainThreadExecutor implements Executor {
       private final Handler handler = new Handler(Looper.getMainLooper());
    
       @Override public void execute(Runnable r) {
         handler.post(r);
       }
     }
    }
    

adapterFactories集合中的CallAdapter.Factory是一个非常重要的概念,它会将请求的对象转换为Call<?>(默认,然后使用enqueue执行异步);如果你使用了RxJava,它会转换为Observable,你可以使用RxJava的链式调用来处理请求与响应。

CallAdapter.Factory有时间会继续做进一步的讲解~

  1. converterFactories集合用来存储转换器工厂,在Retrofit.Builder的构造函数中,会添加默认的BuiltInConverters。Converter.Factory的作用有两个:

    public interface Converter<F, T> {
       T convert(F value) throws IOException;
       abstract class Factory {
         // 响应数据转换为ResponseBody
         public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
           return null;
         }
    
         // 请求数据转换为RequestBody,常用于body
         public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
           return null;
         }
    
         // 请求数据转换为String,常用于Header、Field、Query
         public Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
           return null;
         }
       }
    }
    
  • RequestBody包含了contentType、contentLength以及“请求数据”等。
  • ResponseBody包含了contentType、contentLength以及“响应数据”等。

如果你使用了GsonConverterFactory,那么看起来是这样的

    public final class GsonConverterFactory extends Converter.Factory {
      // ...
      @Override
      public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
          Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new GsonResponseBodyConverter<>(gson, adapter);
      }
      // ...
    }

返回的GsonResponseBodyConverter,最终会使用convert方法,将服务器返回的数据转换为方法的返回类型

   final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
      private final TypeAdapter<T> adapter; // Call<T>或者Observable<T>中的T的转换适配器
      // ...

      // 将ResponseBody转换为T
      @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 Service
Step2中,创建完Retrofit后,我们通过以下代码获得GitHubService的对象service

GitHubService service = retrofit.create(GitHubService.class);

传入GitHubService的Class就能返回一个GitHubService对象,有这么玄乎的事情?我们看下是如何实现的:

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, Object... args)
          throws Throwable {
          // ...省略
          ServiceMethod serviceMethod = loadServiceMethod(method);
          OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.callAdapter.adapt(okHttpCall);
        }
      });
}

看到Proxy、InvocationHandler,熟悉Java动态代理的同学,应该会豁然开朗~,如果不熟悉可以先看下这篇文章:公共技术点之 Java 动态代理

省略次要的代码,invoke方法中剩下两个重要的类:

  • ServiceMethod
    封装了定义在GitHubService中某个方法的“要素”(参数名称、参数注解、方法注解),通俗点讲就是HTTP请求的地址、参数名称和值、方法等。
  • OkHttpCall
    代理类,内部使用okhttp3.Call来实现同步/异步的请求。

我们逐个击破,先看下ServiceMethod的创建过程:

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

主要就是用了一个缓存,同一个Method只会创建一个ServiceMethod对象。
我们重点看下ServiceMethod的创建过程,它也是用的建造者模式

final class ServiceMethod<T> {
  // ...省略
  static final class Builder<T> {
    final Annotation[] methodAnnotations; // 方法注解
    final Annotation[][] parameterAnnotationsArray; // 参数注解
    final Type[] parameterTypes; // 参数类型
    Type responseType; // 返回
    Converter<ResponseBody, T> responseConverter; // Converter.Factory的responseBodyConverter方法返回的对象
    CallAdapter<?> callAdapter; // CallAdapter.Factory的get方法返回对象

    public Builder(Retrofit retrofit, Method method) {
      // ...省略
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      // ...省略
      responseConverter = createResponseConverter();

      // ...解析方法注解,url、header、post/get/put..
      // ...解析参数注解
      return new ServiceMethod<>(this);
    }
  }
}

我们重点看下build方法:

  1. callAdapter是根据ServiceMethod(Method的注解、返回类型),从RetrofitadapterFactories集合中取出一个合适的工厂CallAdapter.Factory,然后使用get方法返回的:

    private CallAdapter<?> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      // ...省略
      Annotation[] annotations = method.getAnnotations();
      try {
        return retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }
    

我们看到,实际上是调用retrofit.callAdapter(returnType, annotations)

   public final class Retrofit {
      // ...省略
      public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
        return nextCallAdapter(null, returnType, annotations);
      }

      public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
        // ...省略
        int start = adapterFactories.indexOf(skipPast) + 1;
        for (int i = start, count = adapterFactories.size(); i < count; i++) {
          CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
          if (adapter != null) {
            return adapter;
          }
        }
        // ...省略
      }
      // ...省略
   }

callAdapter会再调用nextCallAdapter方法,这个方法就是遍历adapterFactories,根据returnType(方法返回类型)和annotations(方法的注解),调用CallAdapter.Factoryget方法获得一个CallAdapter对象。

CallAdapter.Factory的直接继承子类有三种:

  • DefaultCallAdapterFactory
  • RxJavaCallAdapterFactory
  • ExecutorCallAdapterFactory

示例代码没有添加其他CallAdapter.Factory,且返回类型是Call<List<Repo>>,所以会用到Retrofit中的默认工厂:ExecutorCallAdapterFactory

为了不牵扯更多的知识(RxJava相关),我们这里只分析ExecutorCallAdapterFactory,有兴趣的同学可以去看下其他两个的实现。

重点看下ExecutorCallAdapterFactoryget方法:

   final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
      @Override
      public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        // ...省略
        return new CallAdapter<Call<?>>() {
          // ...省略
          @Override public <R> Call<R> adapt(Call<R> call) {
            return new ExecutorCallbackCall<>(callbackExecutor, call);
          }
        };
      }
   }

get方法返回的是CallAdapterCallAdapteradapt方法,正是我们在Retrofitcreate方法中最后调用的:

   // ...省略
   return serviceMethod.callAdapter.adapt(okHttpCall);

adapt返回的ExecutorCallbackCall是一个实现了Call接口的代理类,它的enqueueexecute等方法,最终调用的都是传入的参数okHttpCall(同样也实现了Call接口)的方法。

之所以这样设计,是为了控制enqueue方法返回的结果所在的线程,它使用了Retrofit在构建时的Executor属性来作为线程的调度器(还记得吧?Android中默认的是MainThreadExecutor。):

   static final class ExecutorCallbackCall<T> implements Call<T> {
      final Executor callbackExecutor;
      final Call<T> delegate;

      ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
        this.callbackExecutor = callbackExecutor;
        this.delegate = delegate;
      }

      @Override public void enqueue(final Callback<T> callback) {
        // ...
        delegate.enqueue(new Callback<T>() {
          @Override public void onResponse(Call<T> call, final Response<T> response) {
            callbackExecutor.execute(new Runnable() {
              @Override public void run() {        
                // ...        
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            });
          }
          // ...
        });
      }
   }

callbackExecutor就是MainThreadExecutorcallbackOkHttpCall。我们有理由相信OkHttpCall中大有玄妙,我们稍后会作分析~

  1. responseConverter是通过createResponseConverter()方法创建的:

    private Converter<ResponseBody, T> createResponseConverter() {
       Annotation[] annotations = method.getAnnotations();
       try {
         return retrofit.responseBodyConverter(responseType, annotations);
       } catch (RuntimeException e) { // Wide exception range because factories are user code.
         throw methodError(e, "Unable to create converter for %s", responseType);
       }
    }
    

我们发现调用了retrofitresponseBodyConverter方法:

   public final class Retrofit {
     // ...
     public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
       return nextResponseBodyConverter(null, type, annotations);
     }

     public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast, Type type, Annotation[] annotations) {
       // ...
       int start = converterFactories.indexOf(skipPast) + 1;
       for (int i = start, count = converterFactories.size(); i < count; i++) {
         Converter<ResponseBody, ?> converter =
             converterFactories.get(i).responseBodyConverter(type, annotations, this);
         if (converter != null) {
           //noinspection unchecked
           return (Converter<ResponseBody, T>) converter;
         }
       }
       // ...
     }
     // ...
   }

遍历converterFactories集合,调用Converter.FactoryresponseBodyConverter方法,返回一个Converter对象。如果你的接口返回数据是json格式,那么你会使用GsonConverterFactory来做为结果的转换器:

   public final class GsonConverterFactory extends Converter.Factory {
     // ...
     @Override
     public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
       TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
       return new GsonResponseBodyConverter<>(gson, adapter);
     }
   }

responseBodyConverter方法返回的GsonResponseBodyConverter是用来将json数据格式转换为T,它的方法很简单,关键方法就是convert

   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();
      }
    }
   }

主要就是使用Gson这个框架来做解析,这不是本文的重点,所以不做过多分析了。

至此,ServiceMethod我们已经分析完毕了。
接下来我们看下OkHttpCall吧~


OkHttpCall,让请求飞吧~

OkHttpCall实现了retrofit2.Call接口,实现了我们常用的异步请求enqueue、同步请求execute等方法,其实内部是使用okhttp3.Call来完成最终的网络请求,如果你还不熟悉OkHttp,可以参考这篇文章: Android OkHttp完全解析 是时候来了解OkHttp了

我们以同步方法execute做为示例分析下,enqueue其实是大同小异的:

@Override public Response<T> execute() throws IOException {
  okhttp3.Call call;
  // ...省略
  call = rawCall = createRawCall();
  // ...省略   
  return parseResponse(call.execute());
}

使用createRawCall创建call对象,然后调用call.execute的方法得到Response对象,看下okhttp3.Call的创建过程:

private okhttp3.Call createRawCall() throws IOException {
  Request request = serviceMethod.toRequest(args);
  okhttp3.Call call = serviceMethod.callFactory.newCall(request);
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

这里又看到ServiceMethod,使用toRequest方法,将ServiceMethod中保存的请求信息转换为Request对象,然后使用serviceMethod.callFactory.newCal方法,返回okhttp3.Call对象。我们之前分析过,callFactory实际就是Retrofit中的callFactory对象,而默认的callFactory使用的是OkHttpClient

接上文,得到Response对象,会调用parseReponse方法,最终得到Response<T>对象,T也就是我们在方法中定义的返回类型:

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
  ResponseBody rawBody = rawResponse.body();
  // ...省略
  ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
  // ...省略
  T body = serviceMethod.toResponse(catchingBody);
  return Response.success(body, rawResponse);
}

我们比较关心T是如何生成的,所以看下serviceMethod.toResponse方法:

T toResponse(ResponseBody body) throws IOException {
  return responseConverter.convert(body);
}

responseConverter实际就是GsonResponseBodyConverter,我们在分析ServiceMethod的时候提到过,其实就是用了Gson框架对发挥的json格式数据做了一个“反序列化”操作。

至此,我们已经分析完Retrofit的整个工作流程。


第一次尝试把源码分析的过程整理出来,因为篇幅比较长,所以阅读体验希望大家能多提提意见,您的意见正是我宝贵的财富,谢谢~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容