Retrofit2.0- 原始碼分析

1004145468發表於2018-09-01

1. 閱讀引導

在分析 Retrofit 原始碼之前,你首先得理解動態代理模式,因為Retrofit是通過動態代理的方式進行統一網路請求介面類的處理。Retrofit的程式碼量並不大,只是對OkHttp進行了封裝,用更少的程式碼進行網路請求,明白動態代理模式之後,再看Retrofit網路請求處理流程就很清楚了。少量的程式碼使用大量的設計模式,所以Retrofit框架很值得我們去研究。

2. Retrofit基本使用

  1. 配置Retrofit物件(與OkHttp相同,採用Builder模式)

Retrofit retrofit = new Retrofit.Builder().baseUrl("xxxxx").build();

  1. 建立請求介面類
  public interface NetworkInterface {
    
    @GET("...")
    Call<MyResponse> listRepos(); //不同的方法代表不同的網路請求,可以宣告請求方式(GET、POST..),請求頭Header引數,請求體資訊。
    
    ....
}
複製程式碼
  1. 建立介面類例項

NetworkInterface networkInterface = retrofit.create(NetworkInterface.class);

  1. 呼叫方法,請求實際的網路請求
 Call<MyResponse> call = networkInterface.listRepos();
 call.enqueue(new Callback<MyResponse>() {  //與OkHttp不同,非同步請求會回撥到主執行緒
            @Override
            public void onResponse(Call<MyResponse> call, Response<MyResponse> response) { }

            @Override
            public void onFailure(Call<MyResponse> call, Throwable t) { }
        });
複製程式碼

3. Retrofit流程圖

Retrofit請求處理流程圖.PNG

說明: Retrofit只存在一個CallFactory,但是存在多個CallAdapterFactory和ConvertFactory,針對不同的請求介面方法,Retrofit會通過其返回值,選擇特定的CallAdapterFactory和CovertFactory。

4. Retrofit原始碼分析

4.1 Retrofit建立過程

通過前面基本的使用程式碼可以看出,Retrofit的建立也是採用Builder設計模式,通過new Retrofit.Builder().build()。我們先看看new Retrofit.Builder()的初始化工作。

public static final class Builder {
  ... 
   public Builder() {
      this(Platform.get());
    }

   Builder(Platform platform) {
      converterFactories.add(new BuiltInConverters());
    }
  ...
}
複製程式碼

通過Platform.get()獲取當前平臺物件Platform,然後呼叫它的另一個構造器,在這個構造器中,為ConvertFactory集合新增一個預設的ConvertFactory,不同的ConvertFactory產生的Convert對OkHttp網路請求返回的Response轉化處理不一樣,而預設ConvertFactory的Convert並沒有對Response做太多處理,獲得的資料依舊是Response物件。通過Builder.addConverterFactory(xxx)新增更多的ConvertFactory,比如xxx替換為GsonConverterFactory.create()新增GsonConvertFatory,它產生的GsonConvert就能將Response對映成JavaBean實體。

回到主流程,還是看看Platform.get()是如何處理的吧!

class Platform {

  private static final Platform PLATFORM = findPlatform();        //  靜態工廠模式!

  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {     // 識別當前平臺,如果是Android,就直接返回Android()物件例項
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
     ...
   
    static class Android extends Platform {                    // Platform的子類,Android平臺物件類
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {   // 獲取Android平臺的預設CallAdapterFactory物件
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {       // 獲取Android平臺的預設執行緒執行排程器,其實就是通過Handler用於執行緒切換。
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
  
  }
複製程式碼

總結: 通過new Retrofit.Builder()為ConvertFactory集合中新增一個預設ConvertFactory,建立一個包含預設的CallAdapterFactory、Executor的Android平臺物件。注意,預設的ConvertFactory已經新增到了ConvertFactory集合中了,但是Android物件中的CallAdapterFactory並沒有加入到CallAdapterFactory集合中。

接著看new Retrofit.Builder().build()中的build()方法:

public Retrofit build() {
      if (baseUrl == null) {                  // 強制需要通過.baseUrl("xxxxx")配置url
        throw new IllegalStateException("Base URL required.");  
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();    // 建立CallFactory用於生產Call物件,從這裡也可以看出Retrofit最終還是通過OkHttp傳送網路請求
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();    // 獲取Android平臺物件中的預設Executor,裡面通過Handler進行執行緒切換,上面有講過!
      }

      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);

         // 此處將Android平臺物件中的CallAdapterFactory新增到Retrofit的CallAdapterFactory集合中.
         // 注意同時將Executor也傳入到這個CallAdapterFactory中,那麼工廠生產出來的CallAdapter就也就具有執行緒切換的能力。
       adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); 

      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);                  // 通過Builder建立Retrofit,並將配置引數作為引數傳入
    }
複製程式碼

再看看一下Retrofit的構造:

  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
      @Nullable Executor callbackExecutor, boolean validateEagerly) { 

    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
    this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }
複製程式碼
4.2 核心動態代理程式碼

NetworkInterface networkInterface = retrofit.create(NetworkInterface.class);

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);              //  1.   判斷網路請求介面類的合法性

    if (validateEagerly) {                                  //   2.   是否需要提前對 網路請求介面類 中的方法進行提前處理,即為介面中的每一個方法提前處理成 SeviceMethod(核心類)物件,並快取。
      eagerlyValidateMethods(service);
    }
                                               //   3. 生成動態代理類
    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, @Nullable Object[] args)
              throws Throwable {
              ... 
                                                 // 4. 將介面中的方法處理成serviceMethod。
             ServiceMethod<Object, Object> serviceMethod =  (ServiceMethod<Object, Object>) loadServiceMethod(method); 
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);  // 5. 建立 OkHttpCall物件,傳入serviceMethod物件和呼叫方法實際引數。 
            return serviceMethod.callAdapter.adapt(okHttpCall);  // 6. 將Call物件進行CallAdapter進行轉化( 比如RxCallAdapter將Call轉化為Observable ) 注意Call還沒有被執行,即沒有進行網路請求。
          }
        });
  }
複製程式碼

總結: (一 ) retrofit.create(xx)方法中處理分三步:

    1. 判斷網路請求介面類的合法性
    1. 是否需要提前對 網路請求介面類 中的方法進行預處理
    1. 返回生成動態代理類

(二) 呼叫網路請求介面方法,動態代理類中的invoke()方法被執行,也處理也分三步:

    1. 將對應的執行方法轉化成ServiceMethod物件
    1. 建立OkHttpCall物件
  • 3 OkHttpCall通過CallAdapter進行Call的轉化
4.3 呼叫介面方法

Call call = networkInterface.listRepos();

在通過上面的說明,當呼叫網路請求介面類方法時,就會呼叫invoke方法,傳入通過反射獲取Method和執行方法引數args,因為沒有呼叫call.execute()或call.enqueue(Callback),所以Call並沒有執行。接下來我們具體看看invoke方法體中三部曲吧!

    1. 將對應的執行方法轉化成ServiceMethod物件
  ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);  // 先從快取中取,如果在之前分析的create()中validateEagerly = true 必然從快取中能取到。
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();  // 根據Method建立ServiceMethod物件
        serviceMethodCache.put(method, result);        // 將建立的ServiceMethod進行快取
      }
    }
    return result;
  }
複製程式碼

接下來看看,ServiceMethod的建立!

ServiceMethodBuilder.class

 Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;                         // 1. 將外觀類 Retrofit傳入
      this.method = method;                       
      this.methodAnnotations = method.getAnnotations();  //  2. 獲取方法上的註解(@GET @POST... )
      this.parameterTypes = method.getGenericParameterTypes();   
      this.parameterAnnotationsArray = method.getParameterAnnotations();  // 3. 獲取引數註解(@Query ...)
    }

public ServiceMethod build() {
      callAdapter = createCallAdapter();               // 4. 獲取該方法對應的CallAdapter
      responseType = callAdapter.responseType();  //  5. 獲取該方法的響應型別,比如Response或者自定義的JavaBean
      ... 
      responseConverter = createResponseConverter();   // 6. 根據上面獲取的響應型別獲取對應的Convert

      for (Annotation annotation : methodAnnotations) {  // 7. 解析第二步得到的方法註解
        parseMethodAnnotation(annotation);
      }
      ... 
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
         ... 
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];   // 8. 解析第三步得到的引數註解
         ... 
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

      return new ServiceMethod<>(this);  //  建立ServiceMethod物件
    }

複製程式碼

之前有說過Retrofit中可以有多個ConvertFactory和CallAdapterFactory,通過上面的第4步和第6步獲取該Method對應的ConvertFactory和CallAdapterFactory。這兩種Factory的適配過程近乎一樣,所以這裡只做CallAdapterFactory的配對過程。

private CallAdapter<T, R> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      ... 
      Annotation[] annotations = method.getAnnotations();
      ...
      return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
    }
複製程式碼

Retrofit.class

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
                                                                // typereturn 返回的型別,比如Call、Observable
     ...
    int start = adapterFactories.indexOf(skipPast) + 1;      // 用於做CallAdapterFactory跳過處理,預設start = 0
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
    ...
}
複製程式碼

每一個CallAdapterFactory需要實現一個get(returnType,xxx)方法,如果能處理這個returnType就返回對應的CallAdapter物件。比如預設returnType為Call,那麼就被預設的CallAdapterFactory接受處理,這個CallAdapterFactory在Android平臺類中defaultCallAdapterFactory()獲得(4.1 Retrofit建立過程 有說明)

Android.class

@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
複製程式碼

ExecutorCallAdapterFactory.class

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

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

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }
複製程式碼

總結: ServiceMethod通過Builder模式建立,包含了Retrofit物件,對執行的Method進行剖析,像方法註解、引數註解、引數型別、CallAdapter、ConvertAdapter,所以一個ServiceMethod物件包含了網路請求需要的所有資訊。

    1. 建立OkHttpCall物件

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

OkHttpCall.class

 OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }
複製程式碼
  • 3 OkHttpCall通過CallAdapter進行Call的轉化

serviceMethod.callAdapter.adapt(okHttpCall);

如果介面方法返回型別是Call的話,CallAdapter就是預設的CallAdaterFactory建立的CallAdapter,即ExecutorCallAdapterFactory類中get()方法返回的CallAdapter:

new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };

複製程式碼

接著定位返回的CallAdapter中adapt()方法,最後返回了一個new ExecutorCallbackCall<>(callbackExecutor, call); 物件,代表serviceMethod.callAdapter.adapt(okHttpCall);的執行結束,並向外暴露一個ExecutorCallbackCall物件。

    1. 同步非同步網路請求
// 同步請求
call.execute();
// 非同步請求
call.enqueue(new Callback<MyResponse>() {  //與OkHttp不同,非同步請求會回撥到主執行緒
            @Override
            public void onResponse(Call<MyResponse> call, Response<MyResponse> response) { }

            @Override
            public void onFailure(Call<MyResponse> call, Throwable t) { }
        });
複製程式碼

與同步相比,非同步相對來說複雜一點點,這裡只分析非同步,相信非同步看懂了,同步肯定不在話下。

ExecutorCallbackCall.class

@Override public void enqueue(final Callback<T> callback) {
      ... 
      delegate.enqueue(new Callback<T>() {                 // delegate是由serviceMethod.callAdapter.adapt(okHttpCall); 傳入的,所以最終的網路請求還是通過OkHttpCall進行。
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {       // callbackExecutor 是Android平臺物件類中的MainThreadExecutor 主要將執行緒切換到主執行緒
            @Override public void run() {
              if (delegate.isCanceled()) {
                 ...
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }
複製程式碼

OkHttpCall.class

@Override public void enqueue(final Callback<T> callback) {
   ...
   call.enqueue(new okhttp3.Callback() {                    // 這個Call才是OKHttp中正宗的Call
      @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);
      }
   ... 
}
複製程式碼

5. Retrofit設計模式

  • Builder模式
  • 外觀模式
  • 靜態工廠模式
  • 動態工廠模式
  • 介面卡模式
  • 動態代理模式

相關文章