retrofit 是android开发中对okhttp 进行封装非常常用的库,对开发者有巨大的帮助。其中的可配置,还有注解,动态代理的思想也很值得学习。

1. Retrofit 请求流程

这里以一个小例子开始示例retrofit 是如何开始一个请求的。然后从关键步骤开始分析是如何通过构建请求到okhttp 执行请求返回响应并怎样处理返回的response,并转换为各种格式的。

  1. 首先需要定义一个接口ApiService
interface ApiService {

    companion object{
        fun getApi():ApiService{
            val retrofit = Retrofit.Builder()
                .baseUrl("http://t.weather.sojson.com/api/")
                .build()
            return retrofit.create(ApiService::class.java)
        }
    }

    @GET("http://t.weather.sojson.com/api/weather/city/101030100")
    fun getWeather():Call<ResponseBody>

}

这里定义了一个获取天气的GET请求接口getWeather 返回值是Call类型的。这里的Call是Retrofit定义的而不是Okhttp中定义。在companion object中定义getApi 返回ApiService对象,从而执行请求。也许到这里会觉得太过跳跃,别担心,后面会讲解retrofit.create是如何生成ApiService实现对象的。Retrofit对象通过Builder模式创建,有一点需要注意baseUrl 不能为空,且最有是以"/"结尾的。此外还有ConvertFactory,CallAdapter可以设置,这两者是retrofit强大功能的来源。
2. 调用接口请求

   @Test
    fun testApi(){
        println("request start")
        ApiService.getApi().getWeather().enqueue(object: Callback<ResponseBody>{
            override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
                TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
            }

            override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
                println(buildString {
                    append("response:")
                    append(response.body()?.string())
                })
            }

        })

        val resp = ApiService.getApi().getWeather().execute().body()?.string()
        println("response:${resp}")
    }

到这里通过返回的Call对象执行enqueue 传入回调,或者执行execute返回ResponseBody对象,获取返回的数据,有点跟Okhttp执行请求相似了。只是少了request的构建,简洁不少,也许到这里会觉得没有查多少,retrofit没多大改进,那就大错特错了。这里只是开胃小菜Retrofit还有很强大的饕餮盛宴接下来继续。

2. Retrofit api接口动态代理的创建

关于动态代理这是java中很重要的一点高级功能,动态代理和静态代理的区别这里先不多做详解。动态代理通过反射生成接口的代理实现类

  public <T> T create(final Class<T> service) {
  // 1: 首先会validate service是否是一个interface
    validateServiceInterface(service);
    // 2. 通过Proxy.newProxyInstance 返回一个动态代理对象
    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);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            // 3. 关键代码在这里,通过method 获取一个ServiceMethod
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

以上是标准的动态代理的过程,不同的是这里没有被代理对象target,所以是不能调用代理对象target的接口方法。而是直接调用代理模式中的对方法增强的方法,这里的增强也就是执行网咯请求。这一点需要好好理解动态代理。

3. 对注解的解析以及如何生成RequestFactory

对于Method的处理是通过loadServiceMethod方法。包括处理注解,这也是Retrofit 核心配置的一点解析处理

  ServiceMethod<?> loadServiceMethod(Method method) {
    // 1. 通过HashMap serviceMethodCache 做缓存,以method为key,ServiceMethod为value 
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
      // 2. 关键处理method注解
        result = ServiceMethod.parseAnnotations(this, method);
        // 3. 保存缓存到serviceMethodCache
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

parseAnnotations() 是一个静态方法。

  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
  // 1. RequestFactory 构建了一个RequestFactory 对象
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    // 2. 获取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);
    }
    // 3. 返回值不能为void
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }
    // 4. 
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

其中注释1处,通过RequestFactory.parseAnnotations 通过解析注解获取RequestFactory。这是很关键的一步,在接口api方法中,比如对请求方法Get("url") 和url 会做出解析,并保存到RequestFactory中。

    RequestFactory build() {
    // 1. 解析注解,会取出请求方法和value值
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

     ...

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

这里以GET 方法为例看是怎么取出请求方法和url 和参数的。

private void parseMethodAnnotation(Annotation annotation) {
    ...
    if (annotation instanceof GET) {
    // 1. 判断是否是GET注解,如果是则调用parsehttpMethodAndPath取出
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
    ...
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } 
      ...
        isFormEncoded = true;
      }
    }

    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      ...
      
      // 1. 请求方法赋值
      this.httpMethod = httpMethod;
      this.hasBody = hasBody;

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

      // Get the relative URL path and existing query string, if present.
      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;
      // 通过正则表达式匹配获取params
      this.relativeUrlParamNames = parsePathParameters(value);
    }

以上则是通过注解构建请求的过程,接下来看是如何处理RequestFactory。

4. 对RequestFactory的处理

入口代码在ServiceMethod的静态犯法parseAnnotations中

// 在最后一行返回值中调用
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);

okhttp的请求处理和结果返回值处理都包藏在parseAnnotations中,这里面逻辑复杂,但是条例模块划分是很精妙的。通过对CallAdapter,ConvertFactory的设置。

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
  ...

    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    // 1. isKotlinSusupendFunction kotlin的支持暂时先不管
    if (isKotlinSuspendFunction) {
...
    } else {
    /// 2. 重点在这里获取method的返回值类型Type ,比如返回值Call<ResponseBody>
      adapterType = method.getGenericReturnType();
    }

    // 3. 获取到callAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
  ...
  

    // 4. 获取convertr 用来对response进行处理
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
    // 5. 主要看这里对请求进行处理,callAdapterd是HttpServiceMethod的子类,重写了adapter犯法。
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } ...
  }

首先看到注释3处,这里通过createCallAdapter 获取CallAdapter。callAdapter是Retrofit 中的一个集合中得值,同时又默认的DefaultCallAdapterFactory实现,也可以实现自己的callAdapter。

 private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
    try {
    // 调用retrofit中的callAdapter方法
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
  ....
  }

Retrofit 是怎样处理callAdapter的呢?

  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
 ...

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

可以看到是对callAdapterFactorys进行遍历,并通过returnTYpe,annoation获取能够匹配到的CallAdapter 然后返回。接着会构造为CallAdapted.作为HttpServiceMethod 会执行invoke方法。HttpServiceMethod 有默认实现。

  @Override final @Nullable ReturnT invoke(Object[] args) {
  // OkHttpCall非常关键,这里是对okhttpClient的封装。网络请求在这里进行,
  // 注意看requestFactory 和 callAdapter,responseConverter都传到了okhttpall。
  /// 所有之前的配置在这里都进行了汇总
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

会调用dapter方法,这个方法子类也就是CallAdapted会实现。

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

很清楚了这里会直接调用callAdapter方法。整个调用流程到这里已经较完善了,还有对请求返回值的处理。responseConverter的创建于callAdapter路径差不多,都是最终回到retorfit 中的list进行遍历,查找合适的返回。

5. OkhttpCall 的封装和处理

跟踪CallAdapted的adapter方法,默认是使用DefaultCallAdapterFactory中get方法获取到的  ExecuteCallbackCall类,作为OkhttpCall的代理类。同时也实现了enqueue,execute方法。所以重点还是在OkhttpCall的实现。
通过一个一步请求enqueue方法查看请求过程。

  @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. createRawCall() 创建Okhttp 中的Call,RealCall或者AsynclCall
          call = rawCall = createRawCall();
        ...
      }
    }

   ...
    // 2. 执行okhttp中的异步请求
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
        // 3. 对rqwResponse 进行converter 处理。返回接口注解中的returnType类型数据。
          response = parseResponse(rawResponse);
        } 
        。。。

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

     ...
    });
  }

接下来看parseResponse是怎么进行对response转换处理的。

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();

...

    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
    // 1. 核心代码对responseBody进行 convert
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);
    }
    ...
    }
  }

在注释1的responseConverter是谁呢,是在Retrofit 初始化build的时候已经设置好了,有一个默认值是BuildinConvertory

  @Override public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
      return RequestBodyConverter.INSTANCE;
    }
    return null;
  }

这里是一个默认实现RequestBodyConverter.直接返回ResponseBody。

6. 总结

到这里对Retrofit基本得分析算是完成了。从整体上来看retorift是对Okhttp的请求和Response的封装。核心是通动态代理对Api Interface生成代理类。通过对Method 进行注解解析生成Request和Converter。最终到OkhttpCall 开始进行请求,对返回值ResponseBody 使用Converter进行convert.同时我们可以实现自己的CallAdapter,Conveter比如rxjavaAdapter,和gson conveter的实现

参考资料