深入Retrofit 原理探索~

Posted 初一十五啊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入Retrofit 原理探索~相关的知识,希望对你有一定的参考价值。

我们先来回顾一下 Retrofit 的基本使用

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

interface NetApi 
    @GET("/hotkey/json")
    fun getHotKey(): Call<Response>

    companion object 
        private const val BASE_URL = "https://www.wanandroid.com/"
        fun createApi(): NetApi =
            Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create())
                .build().create(NetApi::class.java)
    


data class HotWords(
    val id: String,
    val name: String,
)

data class Response(
    val errorCode: Int,
    val errorMsg: String,
    val data: List<HotWords>
)

NetApi.createApi().getHotKey().enqueue(object : Callback<Response> 
    override fun onResponse(call: Call<Response>, response: retrofit2.Response<Response>) 
        Log.i(tag, "onResponse: $response.body()?.data")
    

    override fun onFailure(call: Call<Response>, t: Throwable) 
        Log.i(tag, "onFailure: $t.message")
    

)

这样一个基本的网络请求就搞定了,使用很简洁,正是因为其内部使用了大量的设计模式和优秀的架构设计,才得以使其如此方便地进行网络请求,下面来一起瞧瞧 Retrofit 的源码吧~

Retrofit构建过程

使用了建造者模式通过内部静态类 Builder 构建一个 Retrofit 实例,这里列出了部分方法,其他类似。

public static final class Builder 
    private final Platform platform;
    // 网络请求工厂,工厂方法模式
    private @Nullable okhttp3.Call.Factory callFactory;
    // 网络请求地址
    private @Nullable HttpUrl baseUrl;
    // 数据转换器工厂的集合
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    // 网络请求适配器工厂的集合,默认是 ExecutorCallAdapterFactory
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    // 回调方法执行器,用于切换线程
    private @Nullable Executor callbackExecutor;
    // 一个开关,为 true 则会缓存创建的 ServiceMethod
    private boolean validateEagerly;
    
    ...
    
    public Builder baseUrl(String baseUrl) 
      Objects.requireNonNull(baseUrl, "baseUrl == null");
      return baseUrl(HttpUrl.get(baseUrl));
    
    
    public Builder baseUrl(HttpUrl baseUrl) 
      Objects.requireNonNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) 
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      
      this.baseUrl = baseUrl;
      return this;
    
    // 将一个含有 Gson 对象实例的 GsonConverterFactory 放入数据转换器工厂
    public Builder addConverterFactory(Converter.Factory factory) 
      converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    
    
    ...
 

通过 build,我们上面 Builder 类中的参数对象都配置到了 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();
      

      // 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));

      // 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);
    

创建网络请求接口实例过程

使用动态代理的方式拿到所有注解配置后,创建网络请求接口实例。

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

跟踪 loadServiceMethod

  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;
  

parseAnnotations 解析注解配置得到 ServiceMethod,然后加入到 serviceMethodCache 缓存中,是一个 ConcurrentHashMap 。

abstract class ServiceMethod<T> 
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) 
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) 
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    
    if (returnType == void.class) 
      throw methodError(method, "Service methods cannot return void.");
    

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  

  abstract @Nullable T invoke(Object[] args);

通过 RequestFactory 的 parseAnnotations 方法,解析接口方法上的注解,然后封装在 RequestFactory 对象中,将其返回,这个 RequestFactory,主要用于后续创建 OkHttp 请求所需要的 Request 对象。那后面的 HttpServiceMethod.parseAnnotations 又是干什么的呢?往下看。

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) 
  ...
  
  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  if (!isKotlinSuspendFunction) 
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
   else if (continuationWantsResponse) 
    //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
    return (HttpServiceMethod<ResponseT, ReturnT>)
        new SuspendForResponse<>(
            requestFactory,
            callFactory,
            responseConverter,
            (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
   else 
    //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
    return (HttpServiceMethod<ResponseT, ReturnT>)
        new SuspendForBody<>(
            requestFactory,
            callFactory,
            responseConverter,
            (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
            continuationBodyNullable);
  

如果不是 kotlin suspend 函数,使用 CallAdapted 类,如果是 kotlin suspend 函数返回类型是 Response,则使用 SuspendForResponse 类,其余情况使用 SuspendForBody,如 suspend 函数返回类型不是 Response 。一般情况下,我们使用的基本上是属于其余情况,我们来看下 SuspendForBody 类

static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> 
  private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
  private final boolean isNullable;
  ...

  @Override
  protected Object adapt(Call<ResponseT> call, Object[] args) 
    call = callAdapter.adapt(call);

    Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];

    try 
      return isNullable
          ? KotlinExtensions.awaitNullable(call, continuation)
          : KotlinExtensions.await(call, continuation);
     catch (Exception e) 
      return KotlinExtensions.suspendAndThrow(e, continuation);
    
  

跟进 KotlinExtensions.awaitNullable,我们可以看到 SuspendForBody 会将 Response.body 作为协程挂起点的返回值。

suspend fun <T : Any> Call<T?>.await(): T? 
  return suspendCancellableCoroutine  continuation ->
    //协程取消是调用 cancel
    continuation.invokeOnCancellation 
      cancel()
    
    enqueue(object : Callback<T?> 
      override fun onResponse(call: Call<T?>, response: Response<T?>) 
        if (response.isSuccessful) 
          //继续执行相应的协程,将 response.body 作为最后一个挂起点的返回值。
          continuation.resume(response.body())
         else 
          continuation.resumeWithException(HttpException(response))
        
      

      override fun onFailure(call: Call<T?>, t: Throwable) 
        continuation.resumeWithException(t)
      
    )
  

执行请求过程

  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 
          // 创建 OkHttp 的 Call 对象
          call = rawCall = createRawCall();
         catch (Throwable t) 
          throwIfFatal(t);
          failure = creationFailure = t;
        
      
    

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

    if (canceled) 
      call.cancel();
    

    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
          以上是关于深入Retrofit 原理探索~的主要内容,如果未能解决你的问题,请参考以下文章

Retrofit源码解析-动态代理

Retrofit源码解析-动态代理

深入探索Java工作原理:JVM,内存回收及其他

MySQL MVCC原理深入探索

深入浅出Java并发编程指南「难点 - 核心 - 遗漏」让我们一起探索一下CompletionService的技术原理和使用指南

深入浅出Java并发编程指南「源码原理系列」让我们一起探索一下CyclicBarrier的技术原理和源码分析