Retrofit 2.6.2 源码分析

Retrofit 2.6.2 源码分析

原文链接
Retrofit 是对网络请求接口的封装,它内部最终的网络请求还是通过 OkHttp 实现的,但是它使我们只需要编写 java 接口就能创建 OkHttp 需要的请求。

基本使用

// 定义 get 请求接口
interface BaiDuApi {
    @GET("s")
    fun getBaiDu(): Call
}
        // 自定义 OkHttpClient
        val okHttpClient = OkHttpClient.Builder().eventListener(object : EventListener() {
            override fun callStart(call: Call) {
                super.callStart(call)
                Log.d("OkHttpClient", "callStart:${call.request()}")
            }

        }).build()
                // 初始化 Retrofit
        val retrofit = Retrofit.Builder()
            .baseUrl("https://www.baidu.com/")
            .client(okHttpClient)
            .build()

        val baiDuApi = retrofit.create(BaiDuApi::class.java)
        val retrofitCall = baiDuApi.getBaiDu()
        retrofitCall.enqueue(object : retrofit2.Callback {
            override fun onFailure(call: retrofit2.Call, t: Throwable) {
                Log.d("Retrofit", t.toString())
            }

            override fun onResponse(
                call: retrofit2.Call,
                response: retrofit2.Response
            ) {
                Log.d("Retrofit", response.toString())
            }
        })

因为内部是用 OkHttp 所有可以自己初始化一个 OkHttpClient 对象这样我们可以在拦截器里面实现很多自己需要的功能。

还是和上一篇一样,我们从如何使用入手,这里主要涉及到 Retrofit、Call、Callback 几个对象,因为 BaiDuApi 是我们自己创建的接口,但是实际使用的时候还是通过它的方法获取了一个 Call 对象,所以我们先看一下 Retrofit.create 方法里面到底做了什么。

一、Retrofit.create

    // Retrofit.java
    public  T create(final Class service) {
    // 1、
    Utils.validateServiceInterface(service);
    // 5、
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    // 2、
    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 {
            // 3、
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            // 4、
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }
  1. 接口的合法性验证。
  2. 可以看到 create 方法采用了动态代理的方式代理了我们定义的接口的方法。
  3. Object 的方法就直接正常调用,以及一些默认方法的处理。
  4. 通过 loadServiceMethod 处理再执行(看过低版本的人可能会发现 create 和之前稍微有点不一样,但是事实上只是调用的位置有所调整而已,而且这个版本还对 Kotlin 协程做了支持)。注意这个 invoke 方法。
  5. 再回过头看来 eagerlyValidateMethods,其实这里只是采用饿汉的形式,预先遍历了接口的符合要求的方法做 loadServiceMethod 处理。

二、loadServiceMethod

这个方法是将我们定义的接口方法,通过注解解析为一个 ServiceMethod 对象,是核心部分。

     // Retrofit.java
   ServiceMethod loadServiceMethod(Method method) {
    // 1、
    ServiceMethod result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        // 2、
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
  1. 可以看到这里用了一个 Map 保存了 ServiceMethod 对象,method 为 key。
  2. 如果前面没有取到则通过 ServiceMethod.parseAnnotations 解析创建一个,然后放到 Map 中。
  // ServiceMethod.java
  static  ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
    // 3、
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
        // 4、
    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.");
    }
        // 5、
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }
  1. 调用 RequestFactory.parseAnnotations 方法解析请求接口,返回 RequestFactory 为之后构造 OkHttp 的 Request 做准备。
  2. 对接口方法的返回值做非法的判断,如果非法直接抛出异常。
  3. 创建 HttpServiceMethod 对象,这个后面会讲到。

三、RequestFactory.parseAnnotations

对应第二节步骤 3 的解析处理。

  // RequestFactory.java
  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }
        // Builder.build()
    RequestFactory build() {
      // 1、
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
            // 2、没有具体的请求类型
      if (httpMethod == null) {
        throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      if (!hasBody) {
        // isMultipart 但是却没有请求体
        if (isMultipart) {
          throw methodError(method,
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        // isFormEncoded 但是却没有请求体
        if (isFormEncoded) {
          throw methodError(method, "FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }
            // 3、
      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);
      }
            // 4、
      if (relativeUrl == null && !gotUrl) {
        throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError(method, "Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError(method, "Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError(method, "Multipart method must contain at least one @Part.");
      }
            // 5、
      return new RequestFactory(this);
    }

  1. 遍历方法上的注解,并解析,主要是解析方法对应 Http 请求的方法(GET、POST 之类的)以及首部字段。可以从下边的代码看的,请求的类型都是注解,而与之对应的参数都是通过正则匹配解析。
    private void parseMethodAnnotation(Annotation annotation) {
      // PATCH、POST、PUT 类型的请求有请求体,其余的没有
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError(method, "@Headers annotation is empty.");
        }
        // 解析首部字段
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }
    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      if (this.httpMethod != null) {
        throw methodError(method, "Only one HTTP method is allowed. Found: %s and %s.",
            this.httpMethod, httpMethod);
      }
      // 记录请求的方法,是否有请求体
      this.httpMethod = httpMethod;
      this.hasBody = hasBody;

      if (value.isEmpty()) {
        return;
      }

      // 解析 path 信息,以及参数 
      int question = value.indexOf('?');
      if (question != -1 && question < value.length() - 1) {
        // Ensure the query string does not have any named parameters.
        String queryParams = value.substring(question + 1);
        Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
        if (queryParamMatcher.find()) {
          throw methodError(method, "URL query string \"%s\" must not have replace block. "
              + "For dynamic query parameters use @Query.", queryParams);
        }
      }

      this.relativeUrl = value;
      this.relativeUrlParamNames = parsePathParameters(value);
    }
  1. 不合法情况的检查,基本上就是定义接口不符合规泛造成的前后矛盾的情况。

  2. 遍历请求接口方法的参数上的注解,并解析成为 ParameterHandler 保存在一个数组中。

    解析的方法为 parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter) 它的几个参数分别是参数的索引、参数的类型、参数的注解、是否可能是 Kotlin 的 suspend 方法,因为在 Kotlin 编译的时候针对 suspend 方法会给它添加一个为 Continuation 类型的参数,所以这里在解析最后一个参数的时候可能会对参数类型进行判断,如果为 Continuation 则表明这个接口方法是 suspend 的,然后会用 isKotlinSuspendFunction = true 做标记。

    解析为 ParameterHandler 的代码比较多这里就不粘贴代码了,而且它的具体实现也有很多,但是最终使用的时候都会调用它们的 apply 方法,并且传入 retrofit2.RequestBuilder 对象,以及该 ParameterHandler 对应的参数,然后不同类型的 ParameterHandler 会调用 retrofit2.RequestBuilder 做不同的处理来构建请求。

  3. 又是不合法情况的检查。

  4. 返回 RequestFactory 对象到第二节步骤 3。

四、HttpServiceMethod.parseAnnotations

对应第二节步骤 5 的解析处理。这里包含了 Retrofit 两个很重要的操作:

  • 创建适配器可以把 OkHttpCall 适配为我们最初 api 接口定义的方法的返回值。
  • 创建转换器可以把 ResponseBody 转换为我们最终希望回调里面的参数类型的转换器。
  // HttpServiceMethod.java
  static  HttpServiceMethod parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    // 第三节步骤 3 提到的 suspend 方法的标记
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
      // 1、
      Type[] parameterTypes = method.getGenericParameterTypes();
      Type responseType = Utils.getParameterLowerBound(0,
          (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      } else {
        // TODO figure out if type is nullable or not
        // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
        // Find the entry for method
        // Determine if return type is nullable or not
      }
            // 2、
      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      // 3、
      adapterType = method.getGenericReturnType();
    }
        // 4、
    CallAdapter callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    // 5、
    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)");
    }
    // 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.");
    }
        // 6、
    Converter responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    // 7、
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod) new SuspendForResponse<>(requestFactory,
          callFactory, responseConverter, (CallAdapter>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod) new SuspendForBody<>(requestFactory,
          callFactory, responseConverter, (CallAdapter>) callAdapter,
          continuationBodyNullable);
    }
  }
  1. 如果是 Kotlin 的 suspend 方法,那么就获取最后一个参数的泛型的下界通配类型(Continuation 对象的泛型),即原 suspend 方法的返回值类型。如果这个类型是个 retrofit2.Response 类型或者带泛型的类型的话,进一步获取泛型的类型。举个例子:

    suspend fun getResponse():Response 那么最终 responseType = ResponseBody.class,然后标记 continuationWantsResponse = true。

  2. 用步骤 1 获取的类型创建 retrofit2.Call 赋值给 adapterType。给方法的注解插入一个 SkipCallbackExecutor 注解,用于跳过 callbackExecutor 的调度(目前不清楚,后面继续关注)。

    如果没有了解过 Kotlin 和协程的话,不用在意步骤 1 和 2也没关系,等了解了再回来看。

  3. 如果不是 Kotlin 的 suspend 方法,那么很简单直接获取返回值的类型。

  4. 创建一个 CallAdapter 对象,这个对象是用来把 OkHttpCall 适配为我们定义的方法的返回值类型的,这里我们看下拿到的对象的实现是什么。

  // HttpServiceMethod.java
  private static  CallAdapter createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
            // 直接调用 Retrofit 的方法,并进一步调用到 nextCallAdapter
      return (CallAdapter) retrofit.callAdapter(returnType, annotations);
    //省略异常处理
  }
  // Retrofit.java
  public CallAdapter nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
        // 省略一些代码
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    // 通过 callAdapterFactories 查找,那么我们看下这个列表是什么时候创建的
    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()
    public Retrofit build() {
      // 省略一些代码
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        // 如果没定义,获取默认的执行器
        callbackExecutor = platform.defaultCallbackExecutor();
      }
      // 找到了,除了我们在初始化自己的 Retrofit 对象的时候自己可以添加进来
      List callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      // 还有就是和平台相关的默认添加的
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      //省略一些代码
    }
  // Platform.java 
  static class Android extends Platform {
    // 省略一些代码
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override List defaultCallAdapterFactories(
        @Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      // 因为我在 Android 使用所以直接找 Android 平台,
      // 这里根据目标版本的不同,会有点不一样,但是至少会有一个 DefaultCallAdapterFactory
      // Android api 24 对应 Android 7.0 
      // 但是一般我们开发应用会兼容到 4.0 左右,所以就先忽略 CompletableFutureCallAdapterFactory 了
      DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
      return Build.VERSION.SDK_INT >= 24
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
    }
    // 省略一些代码
        // 留意一下这个 Executor,仅仅是使用 handler post 到主线程,就是我们 build 方法中执行器的实现
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());
      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

好了,现在我们终于定位到了创建 CallAdapter 对象的工厂类了 DefaultCallAdapterFactory,马上来看一下获取的具体实现。

  // DefaultCallAdapterFactory.java
  @Override public @Nullable CallAdapter get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    // 省略合法性验证代码
    // 获取泛型上的类型
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
    // 还记得我们步骤 2 中对 Kotlin suspend 方法插入的 SkipCallbackExecutor 注解嘛?生效了
    // 协程会自己调度,所以就不需要我们的调度器了
    final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
        ? null
        : callbackExecutor;

    return new CallAdapter>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call adapt(Call call) {
        // 如果不是协程,我们还是需要调度器来为我们切换线程的,毕竟 OkHttp 的回调不在主线程
        return executor == null
            ? call
            : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }
 
 

我们终于找到了 CallAdapter 的实现,但是现在还没有到它发挥作用的时候,真正使用的时候我们会调用它的 adapt 方法,根据实际的情况会直接返回入参 call,或者进一步分装成 ExecutorCallbackCall 这个我们后面会介绍到。

ps:看过以前版本 Retrofit 的同学可能还会发现这个 DefaultCallAdapterFactory 是以前版本的 DefaultCallAdapterFactory 和 ExecutorCallAdapterFactory 的合体。

  1. 对获取的 CallAdapter.responseType() 合法性的验证。
  2. 创建一个 Converter 对象,用于把 ResponseBody 转换为我们最终希望回调里面的参数类型,根据文章一开始的例子,我们会得到 BufferingResponseBodyConverter 对象(见 BuiltInConverters.java),下边看实现。
// HttpServiceMethod.java
  private static  Converter createResponseConverter(
      Retrofit retrofit, Method method, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
        // 直接调用 Retrofit 的方法,并进一步调用到 nextResponseBodyConverter
        // 过程和 CallAdapter 类似,直接看 Retrofit.Builder 的 build 方法
      return retrofit.responseBodyConverter(responseType, annotations);
    //省略异常处理
  }
    // Retrofit.Builder 对象的 build(),省略很多不相关的代码
    public Retrofit build() {
      List converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      // 首先添加内置转换器工厂,里面实现了多个转换器包括把字节流转换成 ResponseBody,
      // ResponseBody 转换为 java 中的 Void 或者 Kotlin 中的 Unit 时关闭流的操作等
      converterFactories.add(new BuiltInConverters());
      // 有自定义的添加自定义,
      // 我们常用的 GsonConverterFactory 就是把 json 字符串转换为具体对象,
      // 或者把对象转换成 json 字符串
      converterFactories.addAll(this.converterFactories);
      // 平台默认的转换器工厂,下边看一下 Android 平台里面的默认实现
      converterFactories.addAll(platform.defaultConverterFactories());

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  // Platform.java 省略不相关的代码
  static class Android extends Platform {

    @Override List defaultConverterFactories() {
      // 好吧,低版本的就直接没有,如果感兴趣的可以看下 GsonConverterFactory 
      return Build.VERSION.SDK_INT >= 24
          ? singletonList(OptionalConverterFactory.INSTANCE)
          : Collections.emptyList();
    }
  }
  1. 把之前获得的几个对象保存在 HttpServiceMethod 的子类中后返回到动态代理调用方法时候调用 loadServiceMethod(Method method)的地方,见第一节步骤 4。

    HttpServiceMethod 的子类有三个,其中两个是为 Kotlin suspend 方法准备的,可以看到 Retrofit 为了协程做了很多工作,我会以介绍非协程为主,但是还是会讲到协程请况下的处理。没有接触过协程的也不用纠结直接略过,等啥时候了解了再来回味一下。

五、HttpServiceMethod.invoke

回到第一节步骤 4,拿到 HttpServiceMethod 对象之后我们调用了它 invoke 方法,把参数传递进去。

即我们基本使用例子里调用 baiDuApi.getBaiDu() 就会触发:

// Retrofit.java create 方法返回的动态代理中
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

  // invoke 是 ServiceMethod 的方法,具体实现在 HttpServiceMethod 中
  // HttpServiceMethod.java
  @Override final @Nullable ReturnT invoke(Object[] args) {
    // 创建了第四节开始提到的 OkHttpCall 对象,紧接着调用自己的抽象 adapt 方法
    // 1、
    Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }
  protected abstract @Nullable ReturnT adapt(Call call, Object[] args);
  1. HttpServiceMethod.invoke 方法中创建了 OkHttpCall 对象,这个对象实现了 retrofit2.Call 接口,里面是封装了使用 OkHttp 发请求的逻辑。之后又调用了自己的抽象方法 adapt,具体实现在子类中。

    前面提到 HttpServiceMethod 的子类有三个:CallAdapted,SuspendForResponse,SuspendForBody,看类名称也可以猜想到后两个方法是对 Kotlin suspend 方法的支持。

    这里主要讲一下 CallAdapted 类。

  // HttpServiceMethod.java
  static final class CallAdapted extends HttpServiceMethod {
    private final CallAdapter callAdapter;
        // requestFactory 为第二节步骤 3 拿到的 RequestFactory 对象,用于构建 OkHttp 请求
    // callFactory 为 OkHttpClient 对象
    // responseConverter 为第四节步骤 6 拿到的转换器对象,根据本文基础使用的例子为
    // BufferingResponseBodyConverter
    // callAdapter 为第四节步骤 4 中 DefaultCallAdapterFactory.java 创建的对象
    CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
        Converter responseConverter,
        CallAdapter callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }
        // 2、
    @Override protected ReturnT adapt(Call call, Object[] args) {
      return callAdapter.adapt(call);
    }
  }
  1. 步骤 1会调用到 CallAdapted.adapter,这里在注释中解释了一下 CallAdapted 构造方法里面的几个参数便于理解,实际处理还得看 DefaultCallAdapterFactory 创建的 CallAdapter 见下。
    // DefaultCallAdapterFactory.java
    new CallAdapter>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call adapt(Call call) {
        // 如果不是协程,我们还是需要调度器来为我们切换线程的,毕竟 OkHttp 的回调不在主线程
        return executor == null
            ? call // 3、
            : new ExecutorCallbackCall<>(executor, call);
      }
    };
 
 

3、 这里我们会获取到 ExecutorCallbackCall 对象,它的参数分别为把方法放到主线程的 MainThreadExecutor(第四节步骤 4 中提到过)、OkHttpCall。

六、开始调用请求

                // 开始的例子
                // 1、
        val retrofitCall = baiDuApi.getBaiDu()
        retrofitCall.enqueue(object : retrofit2.Callback {
            override fun onFailure(call: retrofit2.Call, t: Throwable) {
                Log.d("Retrofit", t.toString())
            }

            override fun onResponse(
                call: retrofit2.Call,
                response: retrofit2.Response
            ) {
                Log.d("Retrofit", response.toString())
            }
        })
  1. retrofitCall 就是 ExecutorCallbackCall 对象,调用它的 enqueue 方法,传入我们的监听 Callback 。
  // DefaultCallAdapterFactory.java
    // 省略了部分代码
  static final class ExecutorCallbackCall implements Call {
    final Executor callbackExecutor;
    final Call delegate;
    ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
    @Override public void enqueue(final Callback callback) {
      checkNotNull(callback, "callback == null");
            // 2、
      delegate.enqueue(new Callback() {
        @Override public void onResponse(Call call, final Response response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

        @Override public void onFailure(Call call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      }); 
    }
  1. delegate 是 OkHttpCall 对象,使用过 OkHttp 的应该知道它的 enqueue 是执行在子线程的,所以 ExecutorCallbackCall 为我们做的就是把在子线程的回调中,通过 MainThreadExecutor 在主线程中调用 retrofit2.Callback 的回调。当然这个 enqueue 还不是真正的 OkHttp 的 enqueue,它做了封装。
  // OkHttpCall.java     // 太长了,删除部分代码
  @Override public void enqueue(final Callback callback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      if (call == null && failure == null) {
          // 3、
          call = rawCall = createRawCall();
      }
    }
    // 4、
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response response;
            // 5、
          response = parseResponse(rawResponse);
            // 6、
          callback.onResponse(OkHttpCall.this, response);
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }
      private void callFailure(Throwable e) {
          callback.onFailure(OkHttpCall.this, e);
      }
    });
  }
  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;
  }
  1. 创建 OkHttp 的请求的 okhttp3.Call 对象,调用了 requestFactory.create(args) 构造 Request 对象。
  okhttp3.Request create(Object[] args) throws IOException {
    // 这个数组见第三节步骤 3,里面保存了解析出来的参数的 key 等信息
    ParameterHandler[] handlers = (ParameterHandler[]) parameterHandlers;
    int argumentCount = args.length;
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
        headers, contentType, hasBody, isFormEncoded, isMultipart);

    if (isKotlinSuspendFunction) {
            // 如果是 suspend 方法,那么就需要少处理一个,因为最后一个是 Continuation
      argumentCount--;
    }

    List argumentList = new ArrayList<>(argumentCount);
    for (int p = 0; p < argumentCount; p++) {
      argumentList.add(args[p]);
      // 调用 ParameterHandler.apply 往 requestBuilder 里面设置参数
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.get()
        .tag(Invocation.class, new Invocation(method, argumentList))
        .build();
  }
 
 
  1. 发起真正的 OkHttp 异步请求。
  2. 解析响应。
  Response parseResponse(okhttp3.Response rawResponse) throws IOException {
    // 分离响应体和响应头,使得它们可以单独传输处理
    ResponseBody rawBody = rawResponse.body();
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();

    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
        // 请求状态异常的响应
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
    }

    if (code == 204 || code == 205) {
      rawBody.close();
      // 204 和 205 只需要传送响应头
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
        // 调用转换器将 ExceptionCatchingResponseBody 转换成我们需要的数据对象
        // 有兴趣可以看下我们前面提到的 BufferingResponseBodyConverter
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);
  }
  1. 回调操作,这里还是在子线程,通过 ExecutorCallbackCall 里面的流程,调用到主线程,到这里我们就真正的走过了一次 Retrofit 从 create 创建 Call 到发送请求,然后到回调主线程的操作了。

七、HttpServiceMethod 的子类

HttpServiceMethod 继承自 ServiceMethod 是 retrofit 中非常重要的对象,由我们定义的 Api 方法解析而来。

前面提到它有三个子类,第一个 CallAdapted 我们刚才已经讲到过了,那么现在看看另外两个的实现,以及使用场景。

回顾第四节步骤 1 的解释(代码就不再粘贴了,比较多):

如果是 Kotlin 的 suspend 方法,那么就获取最后一个参数的泛型的下界通配类型(Continuation 对象的泛型),即原 suspend 方法的返回值类型。如果这个类型是个 retrofit2.Response 类型或者带泛型的类型的话,进一步获取泛型的类型。举个例子:

suspend fun getResponse():Response 那么最终 responseType = ResponseBody.class,然后标记 continuationWantsResponse = true。

第四节步骤 2 的解释:

用步骤 1 获取的类型创建 retrofit2.Call 赋值给 adapterType。给方法的注解插入一个 SkipCallbackExecutor 注解,用于跳过 callbackExecutor 的调度

第四节步骤 4 中获取 CallAdapter 对象时,DefaultCallAdapterFactory 又对插入的 SkipCallbackExecutor 做处理:

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

下面为 DefaultCallAdapterFactory 返回的 CallAdapter:

    new CallAdapter>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call adapt(Call call) {
        // 因为 executor == null,相当于 adapt 方法啥也没做转接了一下
        return executor == null
            ? call
            : new ExecutorCallbackCall<>(executor, call);
      }
    };
 
 

综上如果不是 suspend 方法,OkHttpCall 会被 ExecutorCallbackCall 包一层,然后再保存在 CallAdapted;否则再根据 continuationWantsResponse 判断,如果是 true 相当于直接把 OkHttpCall 保存在 SuspendForResponse,如果 false 相当于直接把 OkHttpCall 保存在 SuspendForBody。

如果 SuspendForResponse 对应 suspend fun getResponse():Response

那么 SuspendForBody 相当于对应 suspend fun getResponse():ResponseBody

SuspendForResponse

  static final class SuspendForResponse extends HttpServiceMethod {
    private final CallAdapter> callAdapter;
        // 省略构造方法
    @Override protected Object adapt(Call call, Object[] args) {
      // 这个 call 就是 OkHttpCall
      call = callAdapter.adapt(call);
            // suspend 方法编译时会给方法添加一个参数 Continuation 它的泛型为原方法的返回值
      // Continuation 相当于一个回调
      Continuation> continuation =
          (Continuation>) args[args.length - 1];

      try {
        // awaitResponse 是一个 suspend 的拓展方法
        return KotlinExtensions.awaitResponse(call, continuation);
      } catch (Exception e) {
        return KotlinExtensions.yieldAndThrow(e, continuation);
      }
    }
  }
//KotlinExtensions.kt
suspend fun  Call.awaitResponse(): Response {
  // suspendCancellableCoroutine 将异步操作封装为挂起方法
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
        // 这个为 OkHttpCall.enqueue
    enqueue(object : Callback {
      override fun onResponse(call: Call, response: Response) {
        // 调用回调
        continuation.resume(response)
      }

      override fun onFailure(call: Call, t: Throwable) {
        continuation.resumeWithException(t)
      }
    })
  }
}

举个直接用 suspend 请求的例子:

// @GET("s") suspend fun getResponse():Response
GlobalScope.launch(Dispatchers.Main){
  try{
    val response = baiDuApi.getResponse()
    //成功回调
    Log.d("Retrofit", "launch:$response")
    Log.d("Retrofit", "launch:${Thread.currentThread().name}")
  } catch (t : Throwable){
    //失败回调
    Log.d("Retrofit", "launch:${t.message}")
  }
}

SuspendForBody

  static final class SuspendForBody extends HttpServiceMethod {
    private final CallAdapter> callAdapter;
    // 构造方法传入,目前一直是 false,这个判断还是一个 todo,见第四节步骤 1 代码
    private final boolean isNullable;
        // 省略构造方法
    @Override protected Object adapt(Call call, Object[] args) {
      // 这个 call 就是 OkHttpCall
      call = callAdapter.adapt(call);

      Continuation continuation = (Continuation) args[args.length - 1];
      try {
        // awaitNullable,await 实现和上面的 awaitResponse 类似,不再讲
        return isNullable
            ? KotlinExtensions.awaitNullable(call, continuation)
            : KotlinExtensions.await(call, continuation);
      } catch (Exception e) {
        return KotlinExtensions.yieldAndThrow(e, continuation);
      }
    }
  }

结语

如果对 OkHttp 的调用流程分析感兴趣,可以看我之前的一篇文章《OkHttp 4.2.2 源码分析》,版本 4.2.2 为是目前最新的,也是用 Kotlin 实现的。

Retrofit 使我们只需要编写 java 接口就能创建 OkHttp 所需要的请求,以及后续开源的 RxJava2CallAdapterFactory、GsonConverterFactory,让我们也见识到了它设计上的强大。新版本的对 suspend 方法的支持做了很多的工作,但是它的核心原理还是不变的。

其实阅读源码一个是看其中的原理,另一个是看在代码还能怎么写,顺便思考一下日常开发中是否能运用起来。也希望这篇文章能引起一些没有接触过 Kotlin 协程的同学对协程的兴趣。

另外,喜欢的同学,觉得对自己有帮助的同学,务必请花一点点时间帮我点个赞!点赞之交淡如水,但这个很重要!

你可能感兴趣的:(Retrofit 2.6.2 源码分析)