Retrofit源码分析

1,790 阅读3分钟

Retrofit通过对OkHttp的再次封装,简化了网络实现。

1. 代码使用(源码示例SimpleService)

工作流程很简单如下四步:

  • 创建Retrofit对象
  • 创建请求接口代理对象
  • 反射生成OkhttpCall对象
  • 请求和解析ResponseBody返回
Retrofit retrofit =
  new Retrofit.Builder()
    .baseUrl(API_URL)
    .addConverterFactory(GsonConverterFactory.create())
    .build();

// Create an instance of our GitHub API interface.
GitHub github = retrofit.create(GitHub.class);

// Create a call instance for looking up Retrofit contributors.
Call<List<Contributor>> call = github.contributors("square", "retrofit");

List<Contributor> contributors = call.execute().body()

2.创建Retrofit对象

建造者模式创建Retrofit对象

fucntiondescription
client指定要创建的自定义OkHttpClient
callFactory指定要创建的自定义调用工厂
baseUrl指定要创建的基类url 一般包含协议部分、域名部分、端口部分
addConverterFactory添加用于对象序列化和反序列化的转换器工厂
addCallAdapterFactory添加一个支持服务方法返回类型的调用适配器工厂
callbackExecutor添加call执行的线程池
validateEagerly实例化接口对象完成立即验证提供的接口中所有方法的配置

3.创建请求接口代理对象

(1)validateServiceInterface检查接口类及其父类们是否为泛型类,如果是就抛异常
(2)下面就是retrofit核心技术点动态代理:利用Proxy代理请求接口类 ,创建InvocationHandler的实例对象,用来处理被代理类的所有请求方法调用

public <T> T create(final Class<T> service) {
  validateServiceInterface(service);
  return (T)
      Proxy.newProxyInstance(
          service.getClassLoader(),
          new Class<?>[] {service},
          new InvocationHandler() {
            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;
              Platform platform = Platform.get();
              return platform.isDefaultMethod(method)
                  ? platform.invokeDefaultMethod(method, service, proxy, args)
                  : loadServiceMethod(method).invoke(args);
            }
          });
}

平台是android29环境,所以get方法返回的实例是Android24

private static final class Android24 extends Platform {
  static boolean isSupported() {
    return Build.VERSION.SDK_INT >= 24;
  }

  private @Nullable Constructor<Lookup> lookupConstructor;

  @Override
  Executor defaultCallbackExecutor() {
    return MainThreadExecutor.INSTANCE;
  }

  @Override
  List<? extends CallAdapter.Factory> createDefaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    return asList(
        new CompletableFutureCallAdapterFactory(),
        new DefaultCallAdapterFactory(callbackExecutor));
  }
  ...
}

4.生成OkHttpCall对象

  • 反射解析接口方法注解,参数注解生成CallAdapted
  • 调用invoke方法生成OkHttpCall
  • 创建代理类ExecutorCallbackCall代理OkHttpCall

111111.png

4.1反射解析接口方法注解参数注解获得请求类型和urlpath等

需要得到如下信息供Retrofit使用
[7]获得方法注解数组methodAnnotations,参数类型数组parameterTypes,参数注解数组parameterAnnotationsArray

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

[9-10]解析方法注解获得请求类型httpMethod和url路径relativeUrl

private void parseMethodAnnotation(Annotation annotation) {
  ...
  else if (annotation instanceof GET) {
    parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
  }
  ...
}

[11]正则匹配url获得path字符串集合赋值给relativeUrlParamNames

static Set<String> parsePathParameters(String path) {
  Matcher m = PARAM_URL_REGEX.matcher(path);
  Set<String> patterns = new LinkedHashSet<>();
  while (m.find()) {
    patterns.add(m.group(1));
  }
  return patterns;
}

[8]生成方法parameterHandler后面用来替换relativeUrl中的path

RequestFactory build() {
  ...
  int parameterCount = parameterAnnotationsArray.length;
  parameterHandlers = new ParameterHandler<?>[parameterCount];
  for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
    parameterHandlers[p] =
      parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
  }
  ...
  return new RequestFactory(this);
}

[12-22]生成CallAdapted对象
前文已经根据android29环境生成了Platform.Android24,再结合retrofit.build方法,根据请求接口类方法返回值是Call,创建defaultCallAdapterFactory.get()的callAdapter对象和GsonResponseBodyConverter.responseBodyConverter的GsonResponseBodyConverter对象
callFactory是用的默认创建的okhttpClient

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {

  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    ...
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    ...
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    }
    ...
  }
}

4.3调用invoke方法生成OkHttpCall

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
  ...
  @Override
  protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
    return callAdapter.adapt(call);
  }
  
 @Override
 final @Nullable ReturnT invoke(Object[] args) {
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  return adapt(call, args);
 }
}

4.3创建代理类ExecutorCallbackCall代理OkHttpCall

Platform.Android24生成了一个MainThreadExecutor.INSTANCE,所以adapt会生成ExecutorCallbackCall对象

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  private final @Nullable Executor callbackExecutor;
  ...
  @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);
      }
    };
  }
}

android一般情况下都是在UI线程完成UI操作,但是okhttp没有这个能力,所以作者用静态代理模式,实现了enqueue回调从子线程切换到UI线程

static final class ExecutorCallbackCall<T> implements Call<T> {
  ...
  @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()) {
                    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));
          }
        });
  }
  ...
  @Override
  public Response<T> execute() throws IOException {
    return delegate.execute();
  }
  ...
}

目前我们除了生成ExecutorCallbackCall对象还在RequestFactory储存了如下值

参数名来源途径
httpMethod接口方法注解名GET
baseUrl自定义传入api.github.com/
relativeUrl接口方法注解值/repos/{owner}/{repo}/contributors
ParameterHandlerRequestFactory方法parseParameterAnnotation2个ParameterHandler$Path name参数一个是owner一个是repo

5.请求和解析ResponseBody返回

  • 生成okhttp3.Request对象,调用OkhttpClient请求
  • 使用前面生成的responseConverter解析ResponseBody 222222.png

5.1调用OkhttpClient请求,调用OkhttpClient请求

final class OkHttpCall<T> implements Call<T> {
  ...
  @Override
  public Response<T> execute() throws IOException {
    okhttp3.Call call;

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

      call = getRawCall();
    }

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

    return parseResponse(call.execute());
  }

  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;
  }
  ...
}

5.2Gson解析ResponseBody

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