Retrofit 源码分析

368 阅读5分钟

Retrofit的基本使用

  • 创建描述查询信息的接口
    public interface GitHubService {
        @GET("users/{user}/repos")
        Call<List<Repo>> listRepos(@Path("user") String user);
    }
    
  • 创建Retrofit实例
    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();
    
  • 通过retrofit实例的create方法创建接口的代理对象
    GitHubService service = retrofit.create(GitHubService.class);
    
  • 调用接口方法, 返回Call对象
    Call<List<Repo>> call = service.listRepos("111")
    // 返回Call对象之后步骤类似OkHttp, 调用Call的execute同步方法
    // 或者enqueue异步方法并传递一个回调接口的实现
    Call.enqueue(new CallBack<List<Repo>(){
        onResponse()
        onFailure()
    })
    

Retrofit对象

  • Retrofit对象创建 (Builder建造者模式)

    // 成员变量
    // 缓解解析过的接口方法 ServiceMethod
    Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
    okhttp3.Call.Factory callFactory;
    HttpUrl baseUrl;
    List<Converter.Factory> converterFactories;
    List<CallAdapter.Factory> callAdapterFactories;
    // 执行回调方法的执行器
    Executor callbackExecutor;
    boolean validateEagerly;
    
  • Retrofit.Builder
    相比Retrofit类多出了一个Platform对象

    • 成员变量
      // 平台对象
      Platform platform;
      okhttp3.Call.Factory callFactory;
      HttpUrl baseUrl;
      List<Converter.Factory> converterFactories = new ArrayList<>();
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
      Executor callbackExecutor;
      boolean validateEagerly;
      
    • build方法
      // 判断上面的成员变量是否为空, 为空则初始化一个默认的对象
      // 列表类型的则添加一些内置的对象
      // 最后通过这些成员遍历实例化Retrofit实例对象
      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();
        }
      
        List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
        callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
      
        List<Converter.Factory> converterFactories =
            new ArrayList<>(
                1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
      
        converterFactories.add(new BuiltInConverters());
        converterFactories.addAll(this.converterFactories);
        converterFactories.addAll(platform.defaultConverterFactories());
      
        return new Retrofit(
            callFactory,
            baseUrl,
            unmodifiableList(converterFactories),
            unmodifiableList(callAdapterFactories),
            callbackExecutor,
            validateEagerly);
      }
      
  • Platform

    • Android
      Platform的内部类并集成Platform

    • defaultCallbackExecutor() 方法返回回调的执行器

      // Platform 的返回null
      Executor defaultCallbackExecutor() {
          return null;
      }
      // Android 的 返回一个主线程的 Executor
      public Executor defaultCallbackExecutor() {
          return new MainThreadExecutor();
      }
      
      static final class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
          @Override
          public void execute(Runnable r) {
            handler.post(r);
          }
      }
      
  • Retrofit.create 方法
    通过JDK动态代理创建接口的代理对象, 需要提供一个 InvocationHandler 对象实例, 最终方法都会进入其 invoke 方法。查看源码可知最终接口方法调用有2个主要步骤
    1、loadServiceMethod(method) 返回一个 ServiceMethod 实例
    2、调用 ServiceMethod 实例的 invoke 方法

    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);
    }
    
  • Retrofit.loadServiceMethod 方法
    该方法的主要流程是去 serviceMethodCache 中查找, 如果找到直接返回, 没有找到则调用 ServiceMethod.parseAnnotations 进行解析
    serviceMethodCacheRetrofit 的成员变量, 主要用来缓存解析过的接口方法 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 = ServiceMethod.parseAnnotations(this, method);
          serviceMethodCache.put(method, result);
        }
      }
      return result;
    }
    

ServiceMethod

1、是个抽象类
2、提供一个 parseAnnotations 的静态方法来解析接口方法
3、提供一个 invoke 抽象方法对 ServiceMethod 进行调用

abstract class ServiceMethod<T> {
  // 解析接口方法为 ServiceMethod
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    // 1) 解析接口方法的注解
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    
    Type returnType = method.getGenericReturnType();
    
    // 省略一些异常处理代码
    
    // 2) 根据第一步的解析构造具体的 ServiceMethod 实现类
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
    }
    
    // invoke 调用方法
    abstract @Nullable T invoke(Object[] args);
}

RequestFactory

用于生成Request的工厂

  • 成员变量
      private final Method method; // 方法 (是那个接口方法的工厂)
      private final HttpUrl baseUrl; // base url
      final String httpMethod; // 请求方法
      private final @Nullable String relativeUrl; // 相对url
      private final @Nullable Headers headers;  // 请求头
      private final @Nullable MediaType contentType;
      private final boolean hasBody;
      private final boolean isFormEncoded;
      private final boolean isMultipart;
      private final ParameterHandler<?>[] parameterHandlers;
      final boolean isKotlinSuspendFunction; // 是否是kotlin的suspend方法
    
  • parseAnnotations 静态方法
    // 通过内部的Builder创建 RequestFactory 实例
    static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
        return new Builder(retrofit, method).build();
    }
    // Builder的构造方法
    // 获取方法的注解和参数的注解
    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      // 方法对应的注解
      this.methodAnnotations = method.getAnnotations();
      // 方法的参数类型
      this.parameterTypes = method.getGenericParameterTypes();
      // 方法的参数对应的注解
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }
    // build() 中会具体进行解析(代码比较长久不贴了)
    

HttpServiceMethod

1、ServiceMethod的子类
2、本身还是一个抽象类
3、提供 parseAnnotations 静态方法, 最终生成一个具体的ServiceMethod 实现类对象

  • parseAnnotations 静态方法
    主要工作是根据前一步解析的情况来创建一个 HttpServiceMethod 类型的实现类返回
    1、创建 CallAdapter
    2、创建 Converter
    3、创建 HttpServiceMethod 实现类, 需要用到1和2的结果作为参数

    static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
      // 是否为kotlin suspend 方法
      boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
      // 协程是否要返回Response
      boolean continuationWantsResponse = false;
      boolean continuationBodyNullable = false;
      
      // 省略 针对 isKotlinSuspendFunction 的情况进行相应处理
    
      // 创建一个 CallAdapter 实例
      CallAdapter<ResponseT, ReturnT> callAdapter =
          createCallAdapter(retrofit, method, adapterType, annotations);
    
      // 省略一些检查的工作
    
      // 创建一个 Converter 实例
      Converter<ResponseBody, ResponseT> responseConverter =
          createResponseConverter(retrofit, method, responseType);
    
      okhttp3.Call.Factory callFactory = retrofit.callFactory;
      if (!isKotlinSuspendFunction) {
        // 不是Kotlin suspend方法
        return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
      } else if (continuationWantsResponse) {
        // 是kotlin suspend 方法, 并且期望返回 Response
        return (HttpServiceMethod<ResponseT, ReturnT>)
            new SuspendForResponse<>(
                requestFactory,
                callFactory,
                responseConverter,
                (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
      } else {
        // 是kotlin suspend 方法, 只需要Body
        return (HttpServiceMethod<ResponseT, ReturnT>)
            new SuspendForBody<>(
                requestFactory,
                callFactory,
                responseConverter,
                (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
                continuationBodyNullable);
      }
    }
    
  • invoke方法
    上面提到 loadServiceMethod 返回 ServiceMethod 实例后会调用invoke方法, 而 ServiceMethodinvoke 是抽象方法, 具体逻辑在 HttpServiceMethod 实现, 可以看到 HttpServiceMethod 构造了一个 OkHttpCall 对象然后 调用了 adapt 方法。
    其实 HttpServiceMethod 类的 adapt 也是一个抽象方法

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

CallAdapted

上文提到HttpServiceMethodadapter为抽象方法, 在 HttpServiceMethod 类中以内部类的方式提供了三个具体子类, 其中2个和Kotlin 协程相关, 这里只解释非协程的那一个。 从源码可以看到 adapt 最后调用了 CallAdapteradapter 方法, 这个CallAdapter是在构造函数中传递的。 从前面 HttpServiceMethod 的 parseAnnotations 可以看到该对象的创建过程。

1、HttpServiceMethod 的实现类

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
  // CallAdapter 对象
  private final CallAdapter<ResponseT, ReturnT> callAdapter;

  // 构造方法
  // 需要 RequestFactory 、okhttp3.Call.Factory、 Converter、CallAdapter
  CallAdapted(
      RequestFactory requestFactory,
      okhttp3.Call.Factory callFactory,
      Converter<ResponseBody, ResponseT> responseConverter,
      CallAdapter<ResponseT, ReturnT> callAdapter) {
    super(requestFactory, callFactory, responseConverter);
    this.callAdapter = callAdapter;
  }

  // adapter方法, 直接调用 callAdapter 的 adapter方法
  @Override
  protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
    return callAdapter.adapt(call);
  }
}

CallAdapter

1、接口
2、debug发现上面提到的CallAdapter实例对象从 DefaultCallAdapterFactory 中返回

  • DefaultCallAdapterFactory
    get 方法会返回一个匿名的 CallAdapter对象
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
            return null;
        } else if (!(returnType instanceof ParameterizedType)) {
            throw new IllegalArgumentException("Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
        } else {
            final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType)returnType);
            final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null : this.callbackExecutor;
    
            // 返回一个匿名 CallAdapter 的对象
            return new CallAdapter<Object, Call<?>>() {
                public Type responseType() {
                    return responseType;
                }
                // adapter 方法
                // Call是在 HttpServiceMethod 中创建的OkHttpCall对象
                // 所以Adapter方法返回的是一个
                public Call<Object> adapt(Call<Object> call) {
                    // 如果回调的执行器为空则直接返回原来的 OkHttpCall 对象
                    // 否则返回 ExecutorCallbackCall 对象
                    return (Call)(executor == null ? call : new DefaultCallAdapterFactory.ExecutorCallbackCall(executor, call));
                }
            };
        }
    }
    

OkHttpCall

OkHttpCallRetrofit 的一层封装, 里面包含一个 rawCall 成员, 这个成员才是 OKHttp 框架中的 Call, 最终对应的实现类为 OkHttp 中的 RealCall, 通过这个 rawCall 就能发起 OkHttp 层面的网络请求

private @Nullable okhttp3.Call rawCall;
  • enqueue(final Callback callback) 方法
    1、获取到 rawCall 对象, 实际为 RealCall
    2、调用 rawCall 的 enqueue 方法, 并提供一个 CallBack
    3、在内层 CallBack 的 onResponse 中调用 parseResponse 对结果进行进一步处理, 包括使用 convert 将返回数据类型转换成 Java 对象
    4、在外层 CallBack 中 回调用户提供的逻辑

Callback

enqueue执行任务时可以带一个回调接口

  • OkHttp 的回调
    OkHttp的回调包装在AsyncCall中, 是一个Runnable类型, 在线程池中调用, 执行在子线程

  • Retrofit的回调
    Retrofit通过 OkHttpCall 执行enqueue, OkHttpCall 会被进一步包装成 ExecutorCallbackCall, 其中包含一个回调执行器和一个代理对象(OkHttpCall本身), 请求被分发给代理, 回调在回调执行器中执行

  • MainThreadExecutor
    上面提到的回调执行器, 持有一个和UI线程相关的Handler, 把Callback的内容包装成 Runnable 交给handler分发到主线程。所以Retrofit中的回调默认在主线程中执行。

    static final class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());
    
      @Override
      public void execute(Runnable r) {
        handler.post(r);
      }
    }
    

ExecutorCallbackCall

继承Call接口, 内部封装了一个回调执行器和一个Call代理对象。

static final class ExecutorCallbackCall<T> implements Call<T> {
  • 回调执行器
    回调执行器默认在 Retrofit.Builder 的 build 中创建(也可以创建Retrofit对象的时候自己指定一个)

  • 回调执行器默认创建

    Executor callbackExecutor = this.callbackExecutor;
    if (callbackExecutor == null) {
      // platform 在 Android 平台实际为 Plotform 的内部类 Android
      callbackExecutor = platform.defaultCallbackExecutor();
    }
    
    // 返回 MainThreadExecutor
    public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
    
    static final class MainThreadExecutor implements Executor {
      // 包含主线程Looper的Handler
      private final Handler handler = new Handler(Looper.getMainLooper());
    
      @Override
      public void execute(Runnable r) {
        handler.post(r);
      }
    }
    
  • Call代理
    Call代理其实就是对传入的 OkHttpCall对象的引用, 请求的发起仍然通过 OkHttpCall 来完成 (OkHttpCall进一步通过 OkHttp框架的 RealCall来完成)。