1. 程式人生 > >Retrofit原始碼解析

Retrofit原始碼解析

首先看個例項

public class LearnRetrofit {
    public static final String API_URL = "https://api.github.com";

      //建立介面
      public interface GitHub {
        @GET("/repos/{owner}/{repo}/contributors")
        Call<ResponseBody> contributors(
            @Path("owner") String owner,
            @Path("repo") String repo);
      }

      public static void main(String[] args) throws IOException {
        //建立Retrofit物件
        Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(API_URL)
            .build();

        //動態生成一個代理物件
        GitHub github = retrofit.create(GitHub.class);

        //生成一個OKHttpCall的代理物件
        Call<ResponseBody> call = github.contributors("square", "retrofit");

        //返回結果
        Response<ResponseBody> response = call.execute();
        
        //列印資料
        System.out.println(response.body().string());
      }
}

我們從官方文件裡的一個例子開始。我做了一些修改,開始不使用GsonConverter對結果進行轉換,後面會新增,在預設情況下Retrofit只支援將HTTP的響應體轉換換為ResponseBody(OKHttp中的類),預設情況下Retrofit使用BuiltInConverters這個預設的Converter,後面會再次提到。第一步,建立一個介面。第二步,建立一個Retrofit物件,提供BASE_URL等資訊。第三步,建立一個實現了介面的代理物件。第四步,呼叫介面方法,返回一個Call物件。第五步,呼叫execute執行同步請求。第六步,從響應獲取資料。我們跟著步驟一步一步分析。

建立Call
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //Proxy.newProxyInstance()返回一個Github的代理類物件
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          //這個invoke方法會在代理物件的方法中呼叫,第一個引數就是代理物件
          //第二個引數是代理物件呼叫的方法
          //第三個引數方法的引數
          @Override public Object invoke(Object proxy, Method method, 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);
            }
           //呼叫loadMethodHandler
            return loadMethodHandler(method).invoke(args);
          }
        });
  }

這裡使用了動態代理,Proxy.newProxyInstance()返回一個Github的代理類物件。當我們呼叫github這個代理物件的方法比如contributors()時,會呼叫呼叫上述的invoke方法,第一個引數就是代理物件,第二個引數是代理物件呼叫的方法,第三個引數是方法的引數。動態代理可以看我以前的寫的文章,建議完全搞懂動態代理,然後往下看。假設現在我呼叫了github.contributors(“square”, “retrofit”)那麼會呼叫invoke方法,然後呼叫loadMethodHandler()方法。

  MethodHandler loadMethodHandler(Method method) {
    MethodHandler handler;
    synchronized (methodHandlerCache) {
      handler = methodHandlerCache.get(method);
      if (handler == null) {
        //建立MethodHandler 物件
        handler = MethodHandler.create(this, method);
        methodHandlerCache.put(method, handler);
      }
    }
    return handler;
  }

loadMethodHandler()返回一個MethodHandler物件,然後呼叫這個物件的invoke()方法。我們看下這個類。

//核心成員變數
  private final okhttp3.Call.Factory callFactory;
  private final RequestFactory requestFactory;
  private final CallAdapter<?> callAdapter;
  private final Converter<ResponseBody, ?> responseConverter;

//核心方法
  static MethodHandler create(Retrofit retrofit, Method method) {
    //建立CallAdapter
    CallAdapter<?> callAdapter = createCallAdapter(method, retrofit);
    Type responseType = callAdapter.responseType();
    if (responseType == Response.class || responseType == okhttp3.Response.class) {
      throw Utils.methodError(method, "'"
          + Types.getRawType(responseType).getName()
          + "' is not a valid response body type. Did you mean ResponseBody?");
    }
   //建立Converter
    Converter<ResponseBody, ?> responseConverter =
        createResponseConverter(method, retrofit, responseType);
    RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit);
    return new MethodHandler(retrofit.callFactory(), requestFactory, callAdapter,
        responseConverter);
  }

//建立CallAdapter
  private static CallAdapter<?> createCallAdapter(Method method, Retrofit retrofit) {
    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw Utils.methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
      throw Utils.methodError(method, "Service methods cannot return void.");
    }
    Annotation[] annotations = method.getAnnotations();
    try {
      //呼叫Retrofit.callAdapter()
      return retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw Utils.methodError(e, method, "Unable to create call adapter for %s", returnType);
    }
  }

//建立Converter
  private static Converter<ResponseBody, ?> createResponseConverter(Method method,
      Retrofit retrofit, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
    try {
      //呼叫Retrofit.responseBodyConverter()方法
      return retrofit.responseBodyConverter(responseType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw Utils.methodError(e, method, "Unable to create converter for %s", responseType);
    }
  }

在建立MethodHandler這個類的時候,我要建立一個CallAdapter和一個Converter,從流程看,分別呼叫retrofit.callAdapter(returnType, annotations);和retrofit.responseBodyConverter(responseType, annotations);建立。Retrofit的這兩個方法最終呼叫如下兩個方法。

  public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      //從adapterFactories這個LIst獲取
      CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

    StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
        .append(returnType)
        .append(".\n");
    if (skipPast != null) {
      builder.append("  Skipped:");
      for (int i = 0; i < start; i++) {
        builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
      }
      builder.append('\n');
    }
    builder.append("  Tried:");
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
  }



  public <T> Converter<T, RequestBody> nextRequestBodyConverter(Converter.Factory skipPast,
      Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {
    checkNotNull(type, "type == null");
    checkNotNull(parameterAnnotations, "parameterAnnotations == null");
    checkNotNull(methodAnnotations, "methodAnnotations == null");

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      //從converterFactories這個List獲取
      Converter.Factory factory = converterFactories.get(i);
      Converter<?, RequestBody> converter =
          factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<T, RequestBody>) converter;
      }
    }

    StringBuilder builder = new StringBuilder("Could not locate RequestBody converter for ")
        .append(type)
        .append(".\n");
    if (skipPast != null) {
      builder.append("  Skipped:");
      for (int i = 0; i < start; i++) {
        builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
      }
      builder.append('\n');
    }
    builder.append("  Tried:");
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
  }

這兩個方法分別從adapterFactories和converterFactories獲取一個CallAdapter和Converter,我們看下這兩個List是如何構造的。

public Retrofit build() {
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
  }

  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }

  // 建立List儲存CallAdapter.Factory
  List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
  //新增一個預設的CallAdapterFactory
adapterFactories.add(Platform.get().defaultCallAdapterFactory(callbackExecutor));

  // 建立List儲存Converter.Factory
  List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

  return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
      callbackExecutor, validateEagerly);
}


public Builder() {
  // Add the built-in converter factory first. This prevents overriding its behavior but also
  // ensures correct behavior when using converters that consume all types.
 //新增預設的ConverterFactory
  converterFactories.add(new BuiltInConverters());
}

如果我們在構造Retrofit時沒有提供CallAdaCallAdapter.Factory和Converter.Factory,構造時會使用預設值,我看看下程式碼

//新增預設CallAdapterFactory
adapterFactories.add(Platform.get().defaultCallAdapterFactory(callbackExecutor));   

//最終是這個類
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();

  @Override
  public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }

    final Type responseType = Utils.getCallResponseType(returnType);
    //返回匿名CallAdapter類
    return new CallAdapter<Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public <R> Call<R> adapt(Call<R> call) {
        return call;
      }
    };
  }
}

我們看到DefaultCallAdapterFactory生成的匿名CallAdapter類的adapt方法把call原封不動得傳回。再來看看RequestBodyConverter。

  static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
    static final RequestBodyConverter INSTANCE = new RequestBodyConverter();
    
     //將RequestBody原封不動返回,不做任何處理
    @Override public RequestBody convert(RequestBody value) throws IOException {
      return value;
    }
  }

好了,到這裡我們總結下,我們建立了一個MethodHandler物件,建立過程中,我們又建立了一個預設的CallAdapter和一個預設的RequestBodyConverter 。建立完了MethodHandler,我們呼叫了它的invoke()方法。

  Object invoke(Object... args) {
    return callAdapter.adapt(
        new OkHttpCall<>(callFactory, requestFactory, args, responseConverter));
  }

這裡使用了我們剛才建立的預設的CallAdapter,上面我們知道它的adapt()僅僅是返回引數,其他什麼都不做。所以這裡返回的是一個OkHttpCall物件。這個OkHttpCall實現了Call介面。我們總結下,到現在為止,我們僅僅呼叫了這兩句

//動態生成一個代理物件 GitHub github = retrofit.create(GitHub.class);

//生成一個OKHttpCall的代理物件 Call call = github.contributors(“square”, “retrofit”); 所以我們知道Call call = github.contributors(“square”, “retrofit”)返回的就是OkHttpCall物件。接下來我們應該呼叫Response response = call.execute();,我們看下OkHttpCall的execute方法。

呼叫call.execute()
final class OkHttpCall<T> implements Call<T> {
//核心成員變數
  private final okhttp3.Call.Factory callFactory;
  private final RequestFactory requestFactory;
  private final Object[] args;
  private final Converter<ResponseBody, T> responseConverter;

//核心方法
  @Override public Response<T> execute() throws IOException {
    okhttp3.Call call;

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

      if (creationFailure != null) {
        if (creationFailure instanceof IOException) {
          throw (IOException) creationFailure;
        } else {
          throw (RuntimeException) creationFailure;
        }
      }

      call = rawCall;
      if (call == null) {
        try {
           //將任務拋給OKHttp
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException e) {
          creationFailure = e;
          throw e;
        }
      }
    }

    if (canceled) {
      call.cancel();
    }
   
    //轉換結果
    return parseResponse(call.execute());
  }

 //生成okhttp3.Call
  private okhttp3.Call createRawCall() throws IOException {
    //這個callFactory就是OKHttpClient
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

 //將okhttp3.Response轉換成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();

    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
      try {
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }

    if (code == 204 || code == 205) {
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      //這個responseconverter就是預設提供的RequestBodyConverter,當然我們可以替換成自己的converter比如GsonConverter
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }

好了,再次總結下,我們呼叫了OKHttpCall.execute(),該方法生成一個okhttp3.Call將任務拋給OKHttp,完了呼叫parseResponse,用Converter將okhttp3.Response轉換成我們在範型中指定的型別Response response = call.execute(),我指定了okhttp3.ResonseBody。然後返回結果。如果我在構造Retrofit時提供了GsonConverter,addConverterFactory(GsonConverterFactory.create())那麼上面的T body = responseConverter.convert(catchingBody);responseConverter就是GsonConverter。