Retrofit是如何建立的?為什麼要用動態代理

SillyMonkey發表於2019-04-08

Retrofit的出現讓Android的網路請求變得異常簡單,同時可以很好的配合後臺的REST介面。非常值得我們去探究一下它的原理。

Retrofit的使用

通常我們是Retrofit是和Rxjava配合使用,這裡我們不做用法上的過多研究,主要看原理,所以下面的程式碼都是Retrofit的自身API,沒有用Rxjava。

下面是一個普通get請求

1.新建介面

新建介面API.java檔案:

public interface API {
    @GET("請求地址,但是不包括伺服器的地址")
    Call<Response> get(
                            @Query("param1") String param1,//第一個引數
                            @Query("param2") int param2);//第二個引數
}
複製程式碼

在@GET註解裡面加上除去伺服器連結的請求地址,@Query註解裡面是請求的引數名。

2.建立Retrofit服務和請求客戶端

新建一個單例類,RetrofitService.java(名字隨意),在裡面定義一個靜態的OkHttpClient

private RetrofitService() {//構造方法私有化
    }

public static RetrofitService getInstance() {//雙重校驗
        if (instance == null) {
            synchronized (RetrofitService.class) {
                if (instance == null) {
                    instance = new RetrofitService();
                }
            }
        }
        return instance;
    }

private static OkHttpClient mOkHttpClient;

private static void initOkHttpClient() {
    HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor();//日誌攔截器
    mOkHttpClient = new OkHttpClient.Builder().cache(cache)
                            .addInterceptor(logInterceptor)//日誌攔截器,按照需要新增
                            .connectTimeout(10, TimeUnit.SECONDS).build();//連線超時時間
}
複製程式碼

向外提供一個方法,用於獲取剛才的API介面

private volatile static API aPI = null;
    public static API createAPI() {
        if (aPI == null) {
            synchronized (RetrofitService.class) {
                if (aPI == null) {
                    initOkHttpClient();
                    aPI = new Retrofit.Builder()
                            .client(mOkHttpClient)
                            .baseUrl("伺服器地址")
                            .addConverterFactory(GsonConverterFactory.create())//指定json處理庫
                            .build().create(API.class);//將第一步建立的API介面傳入
                }
            }
        }
        return aPI;
    }
複製程式碼

3.開始傳送請求

Call<Response> = call = RetrofitService.getInstance()
                .createShowAPI()
                .get("引數1", "引數2");
                
call.enqueue(new Callback<Response>() {
            @Override
            public void onResponse(Call<Response> call, Response<Response> response) {
                //請求成功的處理
            }

            @Override
            public void onFailure(Call<ShowApiResponse<ShowApiNews>> call, Throwable t) {
                //請求失敗的處理
            }
        });
複製程式碼

Retrofit的核心-動態代理

Retrofit是如何將我們定義的介面方法最後轉化成請求傳送出去呢,這裡就到原始碼去看看

建立者模式

首先來看Retrofit的建立,這裡使用了建立者模式

new Retrofit.Builder()
    .client(mOkHttpClient)
    .baseUrl("伺服器地址")
    .addConverterFactory(GsonConverterFactory.create())//指定json處理庫
    .build().create(API.class);//將第一步建立的API介面傳入
複製程式碼

首先來看Retrofit.Builder()這個類的構造方法

public static final class Builder {
    public Builder() {
      this(Platform.get());
    }
}
複製程式碼

這裡呼叫了一個帶引數的構造方法,先看看Platform.get()是什麼

  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }
  
複製程式碼

Platform.findPlatform

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }
複製程式碼

可以看到,這個Platform類,顧名思義其實就是平臺。在Retrofit中,內建了兩種平臺,一種是Android,一種是Java8。不同的平臺,處理的方式不同。繼續往下看程式碼就明白了

  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

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

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

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

這裡先不深入探究,後面還會再回來,不過我們已經可以看到,Executor類在Android平臺裡是返回了MainThreadExecutor,裡面提供了一個handler,並且這個handler是傳入的主執行緒的Looper,也就是說在execute方法裡面,handler.post實際上是在主執行緒(UI執行緒)執行的。

這裡再回到Retrofit.Builder(),看看那個帶引數的構造方法:

    public Builder() {
      this(Platform.get());
    }

    Builder(Retrofit retrofit) {
      platform = Platform.get();
      callFactory = retrofit.callFactory;
      baseUrl = retrofit.baseUrl;
      converterFactories.addAll(retrofit.converterFactories);
      adapterFactories.addAll(retrofit.adapterFactories);
      // Remove the default, platform-aware call adapter added by build().
      adapterFactories.remove(adapterFactories.size() - 1);
      callbackExecutor = retrofit.callbackExecutor;
      validateEagerly = retrofit.validateEagerly;
    }
複製程式碼

在這個構造方法裡,對各種屬性進行了初始化,來看看這些屬性的定義

    private final Platform platform;//剛才看到的平臺,這裡是Android
    private @Nullable okhttp3.Call.Factory callFactory;//後面在分析
    private HttpUrl baseUrl;//伺服器地址
    private final List<Converter.Factory> converterFactories = new ArrayList<>();//json解析工廠列表
    private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();//後面再分析
    private @Nullable Executor callbackExecutor;//這裡是Android的Executor,在主執行緒執行回撥
    private boolean validateEagerly;//是否提前建立的標誌
複製程式碼

挨個看看這幾個屬性,這裡有些屬性的作用我們後面才知道,不過大部分看命名已經可以看到一些蹊蹺:主要是callFactory和adapterFactories我們現在暫時不知道作用,繼續往下看,在構造方法初始化之後,是呼叫Builder.build()方法

Builder.build()

    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的構造方法,來看看我們剛才疑惑的那兩個屬性怎麼賦值:

callFactory

okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
複製程式碼

callFactory在預設的情況下,其實是一個OkHttpClient,也就是說Retrofit的內部請求原理其實是用的OkHttp。還記得我們最開始建立的時候也傳入了一個靜態類OkHttpClient麼,這之間有什麼關係呢?

new Retrofit.Builder().client(mOkHttpClient)
複製程式碼

Retrofit.Builder().client

    public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }
    
    public Builder callFactory(okhttp3.Call.Factory factory) {
      this.callFactory = checkNotNull(factory, "factory == null");
      return this;
    }
    
複製程式碼

其實client裡面傳入的OkHttpClient也是賦值給了callFactory,所以callFactory就是OkHttp的網路請求客戶端

adapterFactories

// 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));
複製程式碼

建立了一個新的列表,並且加入了預設的CallAdapterFactory,剛才我們知道platform是Android,所以再看看之前的程式碼:

Platform.Android

  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

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

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

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

defaultCallAdapterFactory返回的是ExecutorCallAdapterFactory

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

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }
}
複製程式碼

可以看到構造方法並沒有做什麼,只是將回撥處理類傳入。裡面的其他方法後面呼叫的時候再來看。所以到這裡我們還是不知道adapterFactories是幹嘛的,但是我們看到了這個類裡面有enqueue方法,還有一些處理響應的一些方法,所以我們可以知道它的作用是處理請求和響應,具體的用法後面繼續看原始碼可以看到。

Retrofit.creat

在建立者初始化了所有屬性之後,來到了Retrofit.creat方法

aPI = new Retrofit.Builder()
    .client(mOkHttpClient)
    .baseUrl("伺服器地址")
    .addConverterFactory(GsonConverterFactory.create())//指定json處理庫
    .build().create(API.class);
複製程式碼

Retrofit.creat

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);//驗證是否傳入的為介面類
    if (validateEagerly) {//提前建立,預設為false,這裡跳過
      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, @Nullable Object[] args)
              throws Throwable {
            // 方法定義所在的類,這裡我們是定義在介面裡面,返回false
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            //platform.isDefaultMethod沒做任何處理,直接返回false
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }
複製程式碼

這裡看到了Retrofit的核心,使用動態代理來處理我們在介面中定義的方法。在呼叫我們定義的介面方法時,會來到動態代理類的invoke方法,然後執行最後的三行,在這裡會解析定義的介面方法,並且做相應的處理。

總結

Retrofit在建立的過程中,有這麼一些東西需要我們注意

platform

這個是Retrofit支援的平臺,裡面有Android和Java8,這裡自然是Android

callFactory

執行請求的客戶端,這裡是OkHttpClient,在建立的時候.client傳入

converterFactories

json解析處理工廠陣列,這裡是GsonConverterFactory。進行請求和響應的解析,將json字串轉換為具體的實體類

callAdapterFactories

請求和響應的具體處理介面卡工廠陣列,這裡沒有傳的話預設為ExecutorCallAdapterFactory,如果需要使用rxjava,為RxJava2CallAdapterFactory

callbackExecutor

回撥處理類,用於對回撥資料的處理,這裡是Android平臺預設的MainThreadExecutor,使用Handler在主執行緒中處理回撥。

相關文章