Retrofit 源码分析(一)- 网络请求流程

2,224 阅读12分钟

前言

众所周知🤪,Retrofit内部封装了OkHttp的实现。准确的说,RetrofitOkHttp的基础上进行了上层的扩展,有效地解决了OkHttp代码逻辑调用不怎么优雅的问题,同时为开发者提供更方便的功能模块。Retrofit的官方文档中有给出一个简单的网络请求示例。本文将根据示例,分析Retrofit的源码

本文使用的Retrofit版本为2.9.0

implementation 'com.squareup.retrofit2:retrofit:2.9.0'

流程概要

文档给出的示例代码:

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

// 1. 创建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

// 2. 实例一个GitHubService对象
GitHubService service = retrofit.create(GitHubService.class);

// 3. 发起网络请求
Call<List<Repo>> repos = service.listRepos("octocat");
call.enqueue(new Callback<List<Object>>() {
    @Override
    public void onResponse(@NonNull Call<List<Repo>> call, @NonNull Response<List<Repo>> response) {
        
    }

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

使用Retrofit进行网络请求首先需要定义一个interface,方法即为网络请求相关设置的抽象。接下来就是三步曲了:

  • 创建Retrofit实例,利用Retrofit.Builder()构建一个Retrofit对象,在这个过程中会设置一些参数。比如:
    • 服务端的baseUrl。
    • 若需要自定义一些OkHttp的拦截器的,开发者需要自定义一个OkHttpClient
    • Retrofit支持请求和响应的类型转换的自定义(Converter),以及适配其他库(如RxJava)的自定义(Adapter)。这个会放在后续文章讲解。 这一过程一般会放在应用初始化,Retrofit实例生命周期也会与app一致避免重复创建的开销
  • 实例一个GitHubService对象,利用Retrofit实例构建一个上述定义的interface的对象(ps:其实是Retrofit帮我们虚构的一个对象,后面会讲到)。
  • 发起网络请求,首先会调用具体的方法service.listRepos("octocat"),即表示我们需要请求"users/{user}/repos"这个接口。接下来的调用与OkHttp类似,但值得注意的是这里的CallRetrofit自身定义的

以上就是Retrofit的简单使用流程,接下来会一一分析三部曲的源码。在此之前引用一张有关Retrofit的流程图,涵盖了整个运作流程: image.png

创建Retrofit

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

在创建时,涉及到了外观模式builder模式的思想。其实就是作为Retrofit的一些全局配置逻辑。这里重点关注build()方法

// Retrofit.java
public Retrofit build() {
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
  }
  // 1. OkHttpClient没有自定义时,使用默认的
  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }
  
  // 2. 请求回调时需要使用一个特定的线程池作为回调
  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
  }
  
  // 3. 执行过程中的适配器(Adapter)构建工厂列表
  // Make a defensive copy of the adapters and add the default Call adapter.
  List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
  
  // 4. 请求/响应的数据转换器(Converter)构建工厂列表
  // Make a defensive copy of the converters.
  List<Converter.Factory> converterFactories =
      new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

  // 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());
  converterFactories.addAll(this.converterFactories);
  converterFactories.addAll(platform.defaultConverterFactories());

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

build()方法为Retrofit对象的构造提供必要参数。baseUrl比较好理解,这里就不展开了

callFactory

callFactory即为OkHttp中的OkHttpClient,如果开发者没有设置的话,这里会默认新建一个,以供后续的网络请求。设置是在Retrofit.Builder中的:

// Retrofit.java
public Builder client(OkHttpClient client) {
  return callFactory(Objects.requireNonNull(client, "client == null"));
}

callbackExecutor

callbackExecutor控制网络请求响应后需要回调的线程。这也是Retrofit之于OkHttp的一次封装,可以为开发者做一次线程转换。这里会有一个默认的callbackExecutor,是根据平台区分创建的。此处运用了策略模式的思想。

// Retrofit.java
Builder(Platform platform) {
  this.platform = platform;
}

public Builder() {
  this(Platform.get());
}

// Retrofit.Builder#build()
platform.defaultCallbackExecutor();

// Platform.java
private static final Platform PLATFORM = findPlatform();

static Platform get() {
  return PLATFORM;
}

// 根据jvm区分当前平台为Android还是Java,且默认支持Java8 
private static Platform findPlatform() {
  return "Dalvik".equals(System.getProperty("java.vm.name"))
      ? new Android()
      : new Platform(true);
}

默认的Plantform对象是在Retrofit.Builder的构造方法获取的,findPlatform()方法中会根据jvm区分平台。由于本文偏向Android,所以暂选择Android类作为解析对象。

拓展一个冷知识,在旧版本Retrofit(譬如2.4.0),平台还支持iOS。是利用RoboVM环境使用Java开发iOS的技术。有兴趣可以参考: RoboVM:使用Java开发iOS应用

// Platform.java
static final class Android extends Platform {
  Android() {
    super(Build.VERSION.SDK_INT >= 24);
  }

  @Override
  public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();
  }

  @Nullable
  @Override
  Object invokeDefaultMethod(
      Method method, Class<?> declaringClass, Object object, Object... args) throws Throwable {
    if (Build.VERSION.SDK_INT < 26) {
      throw new UnsupportedOperationException(
          "Calling default methods on API 24 and 25 is not supported");
    }
    return super.invokeDefaultMethod(method, declaringClass, object, args);
  }

  static final class MainThreadExecutor implements Executor {
    private final Handler handler = new Handler(Looper.getMainLooper());

    @Override
    public void execute(Runnable r) {
      handler.post(r);
    }
  }
}

Android#defaultCallbackExecutor返回的是一个MainThreadExecutor,内部持有一个主线程的Handler。它的execute方法即为将一个Runnable发送到主线程的MessageQueue。达到子线程切换到主线程的目的。

callAdapterFactories

callAdapterRetrofit抽象出来的关于okhttp3.Call执行网络请求的封装生成类。详细的介绍放到下文。

// Retrofit.java
public Builder addConverterFactory(Converter.Factory factory) {
  converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
  return this;
}

// Platform.java
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
    @Nullable Executor callbackExecutor) {
  DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
  return hasJava8Types
      ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
      : singletonList(executorFactory);
}
  • 开发者可以根据自身逻辑在Builder的时候通过addConverterFactory添加相关的CallAdapter工厂类。譬如后续文章会介绍的RxJavaCallAdapter
  • Platform类中默认会实现一个defaultCallAdapterFactories方法,用于获取Retrofit自带的。CallAdapter.Factory,这里会根据平台是否适配Java8添加一个CompletableFutureCallAdapterFactory以及默认的DefaultCallAdapterFactory。本文着重介绍DefaultCallAdapterFactory。

converterFactories

Converter转换器,Retrofit在请求和响应时,可以根据Converter作一层数据转换,将上层传递下来的对象转换为网络请求通用的对象,或将响应回来的数据解析成开发者所需要的数据

// Retrofit.java
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());

// Platform.java
List<? extends Converter.Factory> defaultConverterFactories() {
  return hasJava8Types ? singletonList(OptionalConverterFactory.INSTANCE) : emptyList();
}
  • 默认会添加一个BuiltInConverters,支持OkHttp的RequestBody、ResponseBody的转换。
  • 开发者可以根据自身的需要添加自定义的Converter
  • Platform会根据是否支持Java8添加OptionalConverterFactory,这个在本文不作介绍。

小结

至此,build()方法介绍完成,方法中涵盖了网络请求的核心OkHttpClient、回调的线程设置、请求过程中的适配器以及请求和响应的数据转换器

Retrofit#create

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

// Retrofit.java
public <T> T create(final Class<T> service) {
  validateServiceInterface(service);
  return (T)
      Proxy.newProxyInstance(
          service.getClassLoader(),
          new Class<?>[] {service},
          new InvocationHandler() {
            private final Platform platform = Platform.get();
            private final Object[] emptyArgs = new Object[0];

            @Override
            public @Nullable Object invoke(Object proxy, Method method, @Nullable 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);
              }
              args = args != null ? args : emptyArgs;
              return platform.isDefaultMethod(method)
                  ? platform.invokeDefaultMethod(method, service, proxy, args)
                  : loadServiceMethod(method).invoke(args);
            }
          });
}

在定义网络接口层时,我们指定义了一个interface GitHubService,刚开始笔者以为会是像Room之类的库一样采用编译时生成一个Impl类的做法。但Retrofit#create方法可以说是巧妙地运用了动态代理。采用动态代理,在调用具体接口方法时,会触发上述代码的invoke方法,再通过Method对象获取具体的参数及方法、参数的注解,从而转换成OkHttp需要的参数格式

发起网络请求

发起网络请求根据上述的示例代码可分为两步,1、调用具体的网络接口层,2、发起请求

// 1
Call<List<Repo>> repos = service.listRepos("octocat");
// 2
call.enqueue(new Callback<List<Object>>() {
    @Override
    public void onResponse(@NonNull Call<List<Repo>> call, @NonNull Response<List<Repo>> response) {
        
    }

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

调用具体的网络接口层

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

Retrofit#create中提到,调用具体的方法时实际上是调用了InvocationHandler#invoke

// Retrofit.java
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable 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);
  }
  args = args != null ? args : emptyArgs;
  return platform.isDefaultMethod(method)
      ? platform.invokeDefaultMethod(method, service, proxy, args)
      : loadServiceMethod(method).invoke(args);
}

这里会判断是否为Java8的特性interface的默认方法,此处我们只关注loadServiceMethod(method).invoke(args);这一情况。

ServiceMethod<?> loadServiceMethod(Method method) {
  ServiceMethod<?> result = serviceMethodCache.get(method);
  if (result != null) return result;

  synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);
    if (result == null) {
      result = ServiceMethod.parseAnnotations(this, method);
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}

Retrofit#loadServiceMethod

Retrofit#loadServiceMethod内逻辑比较简单,可以理解为是

  • 通过ServiceMethod类解析并保存有关method的信息,如:方法注解、参数注解、参数等。
  • 通过serviceMethodCache,一个Map形成全局缓存,优化二次请求时重复解析的开销

ServiceMethod.parseAnnotations即解析method的信息。

ps:ServiceMethod在低版本是一个实现类,高版本可能是由于需要适配Kotlin的协程所以将ServiceMethod改成抽象类。具体依赖关系:

classDiagram
ServiceMethod <|-- HttpServiceMethod
HttpServiceMethod <|-- CallAdapted
HttpServiceMethod <|-- SuspendForBody

ServiceMethod.parseAnnotations最终调用的是HttpServiceMethod.parseAnnotations,本文不关注有关Kotlin协程的逻辑。下述代码先忽略掉。

// ServiceMethod.java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
  // 解析method的信息,以供后续的网络请求数据组装。
  RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
  // 一些返回类型的校验...
  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

// HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
  boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
  boolean continuationWantsResponse = false;
  boolean continuationBodyNullable = false;
     
  Annotation[] annotations = method.getAnnotations();
  
  Type adapterType;
  if (isKotlinSuspendFunction) {
    // ...
  } else {
    adapterType = method.getGenericReturnType();
  }

  // 通过方法返回类型adapterType和方法注解annotations寻找合适的callAdapter
  CallAdapter<ResponseT, ReturnT> callAdapter =
      createCallAdapter(retrofit, method, adapterType, annotations);
  Type responseType = callAdapter.responseType();
  if (responseType == okhttp3.Response.class) {
    throw methodError(
        method,
        "'"
            + getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
  }
  if (responseType == Response.class) {
    throw methodError(method, "Response must include generic type (e.g., Response<String>)");
  }
  // TODO support Unit for Kotlin?
  if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
    throw methodError(method, "HEAD method must use Void as response type.");
  }

  // 根据方法返回类型responseType寻找合适的converter
  Converter<ResponseBody, ResponseT> responseConverter =
      createResponseConverter(retrofit, method, responseType);

  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  if (!isKotlinSuspendFunction) {
    // 创建对应OkHttp封装的ServiceMethod对象  
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  } else if (continuationWantsResponse) {
    // ...
  } else {
    // ...
  }
}
  • 首先关注ServiceMethod.parseAnnotations中的RequestFactory.parseAnnotations(retrofit, method);主要逻辑是存储method对象中有关请求的参数,并根据参数组装对应的converter用于请求时的数据组装,以及对于注解使用的校验。这里就不过多介绍了。
  • 调用HttpServiceMethod.parseAnnotations
    • 寻找合适的callAdapter
    • 寻找合适的converter
    • 根据以上信息创建一个ServiceMethod对象(CallAdapted

获取callAdapter

// HttpServiceMethod.java
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
    Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
  try {
    //noinspection unchecked
    return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
  } catch (RuntimeException e) { // Wide exception range because factories are user code.
    throw methodError(method, e, "Unable to create call adapter for %s", returnType);
  }
}

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

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

  int start = callAdapterFactories.indexOf(skipPast) + 1;
  for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
    CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
      return adapter;
    }
  }
  
// 抛异常逻辑...
}

前面讲Retrofit.Builder#build时有提到,Retrofit会持有创建callAdapter的工厂类CallAdapter.Factory的列表,即callAdapterFactories。nextCallAdapter方法就是找出能够根据returnTypeannotations的信息创建出合适的callAdapter。以DefaultCallAdapterFactory为例:

// DefaultCallAdapterFactory.java
@Override
public @Nullable CallAdapter<?, ?> get(
    Type returnType, Annotation[] annotations, Retrofit retrofit) {
  if (getRawType(returnType) != Call.class) {
    return null;
  }
  if (!(returnType instanceof ParameterizedType)) {
    throw new IllegalArgumentException(
        "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
  }
  final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

  final Executor executor =
      Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
          ? null
          : callbackExecutor;

  return new CallAdapter<Object, Call<?>>() {
    @Override
    public Type responseType() {
      return responseType;
    }

    @Override
    public Call<Object> adapt(Call<Object> call) {
      return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
    }
  };
}

DefaultCallAdapterFactory#get首先校验的就是该方法的返回类型是否为Call类型。对应的是:

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

留意一下这里返回了一个CallAdapter的匿名类对象,adapt方法是后续流程会调用到的,这个放到后面讲解。

获取converter

获取converter与获取callAdapter的逻辑类似,只是这次是找出合适的Converter.Factory,并创建一个reponseBodyConverter:

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

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

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
    @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
  Objects.requireNonNull(type, "type == null");
  Objects.requireNonNull(annotations, "annotations == null");

  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;
    }
  }
  
// 抛异常逻辑...
}

需要注意的是,Retrofit默认添加的BuiltInConverters其实是无法转换成自定义对象的,可以参考以下代码

@Override
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
    Type type, Annotation[] annotations, Retrofit retrofit) {
  if (type == ResponseBody.class) {
    return Utils.isAnnotationPresent(annotations, Streaming.class)
        ? StreamingResponseBodyConverter.INSTANCE
        : BufferingResponseBodyConverter.INSTANCE;
  }
  if (type == Void.class) {
    return VoidResponseBodyConverter.INSTANCE;
  }
  if (checkForKotlinUnit) {
    try {
      if (type == Unit.class) {
        return UnitResponseBodyConverter.INSTANCE;
      }
    } catch (NoClassDefFoundError ignored) {
      checkForKotlinUnit = false;
    }
  }
  return null;
}

即我们按照示例代码创建的Retrofit对象其实并没有将响应数据转换成自定义对象的能力,所以常规的是添加一个GsonConverterFactory,代码会修改成这样:

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

implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

ServiceMethod#invoke

回到InvocationHandler#invoke中,执行完loadServiceMethod后会调用ServiceMethod#invoke

// ServiceMethod.java
abstract @Nullable T invoke(Object[] args);

// HttpServiceMethod.java
@Override
final @Nullable ReturnT invoke(Object[] args) {
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  return adapt(call, args);
}

// CallAdapted.java
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
  return callAdapter.adapt(call);
}

由于ServiceMethod#invoke是一个抽象方法,由HttpServiceMethod实现。这里invokeHttpServiceMethod中被声明为了finalps:HttpServiceMethod也是一个抽象类)。HttpServiceMethod#invoke方法最终会调用adapt,adapt由子类实现。

  • HttpServiceMethod#invoke中新建了一个OkHttpCall对象,该对象继承自Call接口(没错,和上面看到那个Call是同一个,这个是具体的实现类)。该类封装了OkHttp的网络请求逻辑,是真实执行网络请求的地方
  • CallAdapted#adapt中callAdapter即为上一节所提到的由DefaultCallAdapterFactory#get返回的匿名CallAdapter对象。调用其adapt方法,会返回一个ExecutorCallbackCall对象,也是继承自Call接口。这里采用了装饰器的思想。
// DefaultCallAdapterFactory.java
@Override
public Call<Object> adapt(Call<Object> call) {
  return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}

所以回到应用层,返回的Call对象在这种情况下实际是一个ExecutorCallbackCall对象

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

发起请求

由上一节可知,这里的call对象类型为ExecutorCallbackCall

call.enqueue(new Callback<List<Object>>() {
    @Override
    public void onResponse(@NonNull Call<List<Repo>> call, @NonNull Response<List<Repo>> response) {
        
    }

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

ExecutorCallbackCallDefaultCallAdapterFactory的静态内部类,这里采用类装饰器的思想。

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) {
      Objects.requireNonNull(callback, "callback == null");

      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              callbackExecutor.execute(
                  () -> {
                    if (delegate.isCanceled()) {
                      // Emulate OkHttp's behavior of throwing/delivering an IOException on
                      // cancellation.
                      callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                      callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                  });
            }

            @Override
            public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }

调用enqueue后实际上是调用了delegate的enqueue(ps:这里的delegate即为上述所说的OkHttpCall)。而ExecutorCallbackCall在这里的作用是切换线程。callbackExecutor即为在Retrofit初始化时设置的那个,Android平台默认就是主线程

关于CallExecutorCallbackCallOkHttpCall的关系

classDiagram
Call <|-- ExecutorCallbackCall
Call <|-- OkHttpCall
OkHttpCall <-- ExecutorCallbackCall

OkHttpCall

我们先来看看一个简单的OkHttp用例,对应Retrofit示例代码

// 1. 新建一个Call,ps:注意这里是okhttp3.Call和Retrofit#Call要注意区分
String user = "abc";
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder().get()
        .url("https://api.github.com/users/" + user + "/repos")
        .build();
okhttp3.Call call = client.newCall(request);
// 2. 发起请求
call.enqueue(new Callback() {
    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
        
    }

    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {

    }
});

简单描述一下:

  1. 利用OkHttpClient新建一个okhttp3.Call对象,注意这里要和Retrofit的Call接口作区分。
  2. 调用okhttp3.Call#enqueue发起请求

继续回到OkHttpCall:

// OkHttpCall.java
@Override
public void enqueue(final Callback<T> callback) {
  Objects.requireNonNull(callback, "callback == null");

  okhttp3.Call call;
  Throwable failure;

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

    call = rawCall;
    failure = creationFailure;
    if (call == null && failure == null) {
      try {
        // 1. 新建一个okhttp3.Call
        call = rawCall = createRawCall();
      } catch (Throwable t) {
        throwIfFatal(t);
        failure = creationFailure = t;
      }
    }
  }

  if (failure != null) {
    callback.onFailure(this, failure);
    return;
  }

  if (canceled) {
    call.cancel();
  }

  // 2. 发起网络请求
  call.enqueue(
      new okhttp3.Callback() {
        @Override
        public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
          Response<T> response;
          try {
            response = parseResponse(rawResponse);
          } catch (Throwable e) {
            throwIfFatal(e);
            callFailure(e);
            return;
          }

          try {
            callback.onResponse(OkHttpCall.this, response);
          } catch (Throwable t) {
            throwIfFatal(t);
            t.printStackTrace(); // TODO this is not great
          }
        }

        @Override
        public void onFailure(okhttp3.Call call, IOException e) {
          callFailure(e);
        }

        private void callFailure(Throwable e) {
          try {
            callback.onFailure(OkHttpCall.this, e);
          } catch (Throwable t) {
            throwIfFatal(t);
            t.printStackTrace(); // TODO this is not great
          }
        }
      });
}

上面代码对比纯OkHttpRetrofit的OkHttpCall就不难理解了。

  • 新建一个okhttp3.Call时,用到之前在ServiceMethod.parseAnnotations创建的RequestFactory对象,主要作用是通过之前保存Method的信息,组装一个okhttp3.Request对象。(ps:数据组装的时候也会使用到Converter)。
    // OkHttpCall.java
    private okhttp3.Call createRawCall() throws IOException {
      okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
      if (call == null) {
        throw new NullPointerException("Call.Factory returned null.");
      }
      return call;
    }
    
  • 网络请求响应后,会调用OkHttpCall#parseResponse,在正常200响应码的情况下就会使用responseConverter转换响应数据。
    // OkHttpCall.java
    Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
      ResponseBody rawBody = rawResponse.body();
    
      // ...
    
      ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
      try {
        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;
      }
    }
    
    由于我们使用的是GsonConverterFactory,最终就会到GsonResponseBodyConverter#convert。其实就是使用Gson做一次json解析
    // GsonResponseBodyConverter.java
    @Override
    public T convert(ResponseBody value) throws IOException {
      JsonReader jsonReader = gson.newJsonReader(value.charStream());
      try {
        T result = adapter.read(jsonReader);
        if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
          throw new JsonIOException("JSON document was not fully consumed.");
        }
        return result;
      } finally {
        value.close();
      }
    }
    
    ps:这里解析的T类型即为刚开始定义的List<Repo>

设计模式

总结一下本文所遇到的设计模式思想(欢迎在评论补充和修正):

  • Retrofit的创建用到了外观模式构造器模式(Builder模式)
  • Retrofit#create用到了动态代理,将定义的interface实例成一个虚构的对象。
  • 关于CallAdatperConverter的获取用到了策略模式
    • 根据定义方法的返回类型(譬如:Call),获取合适的CallAdatper
    • 根据响应数据需要转换的数据类型(譬如:Call<T>中的T),获取合适的responseConverter。
  • CallAdatperConverter的创建用到了工厂模式CallAdatper.FactoryContercer.Factory)。
  • CallAdatper用到了适配器模式,即封装了OkHttp能力的OkHttpCall可以适配不同库的调用,譬如ExectorCallbackCall/RxJava/Java8等。Converter的思想也是如此

最后

本文主要通过Retrofit文档给出的示例代码,简单解析了对于OkHttp整个网络请求的流程封装。阅读源码时,需要注意定义的接口方法对应会选择哪个CallAdapter和哪个Converter,还有Callokhttp3.Call的混淆等问题。了解整个流程后对于查看其他扩展(譬如RxJava)会有所帮助

参考文章:

Retrofit中的设计模式

【Bugly 干货分享】深入浅出 Retrofit,这么牛逼的框架你们还不来看看?