Retrofit源碼解析

知其然方能知其所以然。。。。。。。。。。。。。。。

尊重他人的勞動成果,轉載請標明出處:http://blog.csdn.net/gengqiquan/article/details/52778522, 本文出自:【gengqiquan的博客】

對於Retrofit,還不會用的可以看這篇文章Retrofit使用教程(二)

對Retrofit做封裝以便更方便的使用可以看這篇文章淺談Retrofit封裝-讓框架更加簡潔易用

既然是好的框架,我們當然要拿來用,但同時也應該去了解框架的優點和好的設計思想。本篇博客就帶大家來一起走進Retrofit源碼的世界。
Retrofit 獨樹一幟的把請求採用了接口,方法和註解參數(parameter annotations)來聲明式定義一個請求應該如何被創建的方式。 如果你已經使用過它了,你應該記得他的實例創建是這樣的

   Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(StringConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .client(OkhttpProvidede.okHttpClient(mAppliactionContext))
                    .build();

            RetrofitHttpService Service =
                    retrofit.create(RetrofitHttpService.class);

2.0版本適配器並沒有打包進retrofit裏,需要用戶自己去額外引用。
也就是需要額外添加這兩個依賴

  compile 'com.squareup.retrofit2:converter-gson:2.1.0'
  compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

上面一個是gson 解析的,下面一個是RXJava的。根據需要添加

首先我們來看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> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

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

builder()方法進行了一些簡單的檢查,構建了默認的請求工廠,檢查了適配器工廠和轉換器工廠,
retrofit.create(RetrofitHttpService.class);方法,採用方法註解定義請求的類型。

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @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);
            }
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

傳入的是請求方法接口,類似於這樣的

  public interface RetrofitHttpService {

    @GET()
    Call<String> get(@Url String url, @QueryMap Map<String, String> params, @Header("Cache-Time") String time);

    @FormUrlEncoded
    @POST()
    Call<String> post(@Url String url, @FieldMap Map<String, String> params, @Header("Cache-Time") String time);
}

一步步看create方法
首先是 Utils.validateServiceInterface(service);
對接口類進行了檢查

 static <T> void validateServiceInterface(Class<T> service) {
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }
    // Prevent API interfaces from extending other interfaces. This not only avoids a bug in
    // Android (http://b.android.com/58753) but it forces composition of API declarations which is
    // the recommended pattern.
    if (service.getInterfaces().length > 0) {
      throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
    }
  }

確保了service類必須爲接口且不能繼承於其他接口
validateEagerly是用戶在構建retrofit是自己配置的,是否需要預加載接口內的非默認方法,如果需要就進行預加載到

 private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method)) {
        loadServiceMethod(method);
      }
    }
  }

  ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

第一道菜來了

return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @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);
            }
         ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);      }
        });
  }

返回的是一個動態代理類,也就是說我們調用的那些自定義的接口,比如上面我定義的get(),和post(),都是通過這個動態代理單例去進行的,這樣的好處是用戶不需要去關注請求發起時需要做哪些事,所有的一些都交由動態代理類去完成。而代理內部是如和調用請求的呢?
判斷是否屬於延遲執行方法,是則直接執行。
判斷是否屬於接口默認方法,是則執行
如果不滿足上述條件。則確定爲retrofit所採用的註解方法

  ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);

看loadServiceMethod的構建


  ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

再次builder,在builder類實例化的時候獲取之前我們在service裏定義的各種類型的註解

 public Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

看build()方法,很長的一段代碼

public ServiceMethod build() {
//創建請求適配器
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      //創建響應體轉換器
      responseConverter = createResponseConverter();

      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);//解析方法註解,下面單獨看
      }

     //省略一系列判斷代碼

      int parameterCount = parameterAnnotationsArray.length;
      //參數註解類,下面我們單獨看
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
       //省略一大堆參數註解的解析判斷代碼
       }
      return new ServiceMethod<>(this);
    }

先看parseMethodAnnotation()方法,解析接口方法的註解,告訴retrofit改方法是哪種請求方式

private void parseMethodAnnotation(Annotation annotation) {
      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);
        if (!Void.class.equals(responseType)) {
          throw methodError("HEAD method must use Void as response type.");
        }
     //下面省略的代碼和上面相同類型
      }
    }

再看ParameterHandler類


abstract class ParameterHandler<T> {
  abstract void apply(RequestBuilder builder, T value) throws IOException;

  final ParameterHandler<Iterable<T>> iterable() {
  }

  final ParameterHandler<Object> array() {

  }

  static final class RelativeUrl extends ParameterHandler<Object> {
    @Override void apply(RequestBuilder builder, Object value) {
      builder.setRelativeUrl(value);
    }
  }

  static final class Header<T> extends ParameterHandler<T> {
   private final String name;
    private final Converter<T, String> valueConverter;

    Header(String name, Converter<T, String> valueConverter) {
      this.name = checkNotNull(name, "name == null");
      this.valueConverter = valueConverter;
    }

    @Override void apply(RequestBuilder builder, T value) throws IOException {
      if (value == null) return; // Skip null values.
      builder.addHeader(name, valueConverter.convert(value));
    }

  }

  static final class Path<T> extends ParameterHandler<T> {
  //省略類裏面代碼,免得大家看的頭疼,下同
  }

  static final class Query<T> extends ParameterHandler<T> {

  }

  static final class QueryMap<T> extends ParameterHandler<Map<String, T>> {

  }

//省略一系列參數註解對應的類
}

雖然只貼出來一部分,大家也能看出來這個類就是我們再service裏定義的接口方法的那些參數註解,每個註解靜態類都實現了一個構造函數外加一個apply方法。這個apply後面會遇到。

接下來交由ServiceMethod的callAdapter 去進行層層解析,然後交由OkHttpCall 去執行具體的請求
這個callAdapter 是可以設置的,比如上面的例子我們設置的就是addCallAdapterFactory(RxJavaCallAdapterFactory.create())
如果不設置的話,retrofit會默認創建一個

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

callAdapter 處理過程我們後面再看,先看OkHttpCall
先看發送請求

 @Override public synchronized Request request() {
    okhttp3.Call call = rawCall;
    if (call != null) {
      return call.request();
    }
    if (creationFailure != null) {
      if (creationFailure instanceof IOException) {
        throw new RuntimeException("Unable to create request.", creationFailure);
      } else {
        throw (RuntimeException) creationFailure;
      }
    }
    try {
      return (rawCall = createRawCall()).request();
    } catch (RuntimeException e) {
      creationFailure = e;
      throw e;
    } catch (IOException e) {
      creationFailure = e;
      throw new RuntimeException("Unable to create request.", e);
    }
  }

裏面有

  return (rawCall = createRawCall()).request();

這一句,我們看看他裏面做了什麼

 private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

裏面再次調用了serviceMethod的toRequest(args);方法,看方法內部


  /** Builds an HTTP request from method arguments. */
  Request toRequest(Object... args) throws IOException {
  //省略代碼
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args != null ? args.length : 0;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
    }

    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.build();
  }

可以看到調用了handlers的apply方法,這個就是之前的註解類裏所實現的apply。

再看OkHttpCall相應請求的代碼

  @Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");

    okhttp3.Call call;
    Throwable failure;
    //這裏省略代碼
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }
   //這裏省略代碼
}
@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 {
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException e) {
          creationFailure = e;
          throw e;
        }
      }
    }

    if (canceled) {
      call.cancel();
    }

    return parseResponse(call.execute());
  }

分爲同步和異步執行請求,可以看到,只要獲得相應了就直接走 parseResponse();方法,我們來看看這個方法

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 {
      T body = serviceMethod.toResponse(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;
    }
  }

可以看到方法內部直接對Response.code()值進行了判斷,把非OK的狀態的情況全部調用了Response.error()方法,再來看這個Response.error()方法

public static <T> Response<T> error(ResponseBody body, okhttp3.Response rawResponse) {
    if (body == null) throw new NullPointerException("body == null");
    if (rawResponse == null) throw new NullPointerException("rawResponse == null");
    if (rawResponse.isSuccessful()) {
      throw new IllegalArgumentException("rawResponse should not be successful response");
    }
    return new Response<>(rawResponse, null, body);
private Response(okhttp3.Response rawResponse, T body, ResponseBody errorBody) {
    this.rawResponse = rawResponse;
    this.body = body;
    this.errorBody = errorBody;
  }

再次構建了一個出錯的Response作爲返回,而不是如一般網絡框架那樣返回一堆錯誤信息或者直接拋出異常

有點頭疼,今天先寫到這裏,下篇我們再一起看看CallAdapter是怎麼處理註解接口方法

我建了一個QQ羣(羣號:121606151),用於大家討論交流Android技術問題,有興趣的可以加下,大家一起進步。

發佈了40 篇原創文章 · 獲贊 85 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章