Retrofit源碼解析

轉載請注明:http://www.qinglinyi.com/posts/retrofit/

認識Retrofit2

*** A type-safe HTTP client for Android and Java ***
意思就是說Retrofit是一個Android和Java的類型安全的Http客戶端/請求工具。
對于Retrofit的詳細介紹我們可以通過官網了解。

Retrofit2 使用

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

Retrofit retrofit = new Retrofit.Builder()
  .baseUrl("https://api.github.com")
  .build();

GitHubService service = retrofit.create(GitHubService.class);

Call<List<Repo>> repos = service.listRepos("octocat");

repos.enqueue(new Callback<List<Repo>>() {
  @Override
  public void onResponse(Response<List<Repo>> response) {
    // do something  
  }
  @Override
  public void onFailure(Throwable t) {
    // do something
  }
});

或者這樣:

 public interface GitHubService {
   @GET("users/{user}/repos")
   Observable<List<Repo>> listRepos(@Path("user") String user);
 }
 
 Retrofit retrofit = new Retrofit.Builder()
   .baseUrl("https://api.github.com")
   .addConverterFactory(GsonConverterFactory.create())
   .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
   .build();

 GitHubService service = retrofit.create(GitHubService.class);
 
 service.listRepos("octocat")
               .observeOn(AndroidSchedulers.mainThread())
               .subscribeOn(Schedulers.io())
               .subscribe();

** 注意:** 詳細的使用,大家可以查看其它教程。

Retrofit2是怎么工作的

如上面的使用中我們可以看到:

  1. 通過Retrofit.Builder()創建Retrofit。
  2. 調用Retrofit的create()方法將生成接口GitHubService的實例。
  3. 調用GitHubService的listRepos()方法返Call<List<Repo>>
  4. 執行Call<List<Repo>>的enqueue方法在回調中處理返回的List<Repo>

Retrofit2的主要成員

那么在了解Retrofit2到底是怎么工作的之前我們先認識一下Retrofit2的主要成員:

  1. Call(接口)--向服務器發送請求并返回響應的調用

  2. CallAdapter(接口)--Call的適配器,用來包裝轉換Call

  3. CallBack(接口)--顧名思義Call的回調,Call執行時的回調

  4. Converter(接口)--數據轉換器,將一個對象轉化另外一個對象

  5. CallAdapter.Factory(接口)--CallAdapter的工廠,通過get方法獲取CallAdapter

  6. Converter.Factory(抽象類) -- 數據轉換器Converter的工廠

    • responseBodyConverter -- 將服務器返回的數據轉化ResponseBody。可以理解為數據解析的轉換器
    • requestBodyConverter -- 將GitHubService.listRepos()中的Body,Part和PartMap注解轉換為RequestBody(OkHttp3),以便http請求的時候使用。
    • stringConverter -- 將Field,FieldMap 值,Header,Path,Query,和QueryMap值轉化為String,以便http請求的時候使用。
  7. MethodHandler -- 處理、執行GitHubService方法的類

  8. RequestFactory -- 創建OkHttp請求的Request

  9. RequestFactoryParser -- 解析GitHubService.listRepos()方法的注解和參數,生成RequestFactory。(會用到requestBodyConverter,stringConverter)

  10. OkHttpCall -- 實現Call接口,獲取傳入的Call(代理Call,通過Retrofit.callFactory生成的)執行請求,獲取數據并使用responseConverter進行解析。

創建Retrofit

通過Retrofit.Builder創建Retrofit,先看看Retrofit.Builder都有什么。

Retrofit.Builder:

    private okhttp3.Call.Factory callFactory; // okhttp3 的網絡請求Call
    private BaseUrl baseUrl; // 網絡請求地址的基礎部分(公共部分),Retrofit會自動拼接成真正的請求地址
    private List<Converter.Factory> converterFactories = new ArrayList<>();
    private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
    private Executor callbackExecutor; // 回調的Executor
    private boolean validateEagerly;// 若為真,會提交調用eagerlyValidateMethods方法,提前加載MethodHandler
    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

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

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(Platform.get().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);
    }

通過build的方法,我可以知道Retrofit.Builder提供一個默認的OkHttpClient,一個默認的CallAdapterFactory。
默認Platform:

  CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
    if (callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapter.FACTORY;
  }

Platform.get().defaultCallAdapterFactory(callbackExecutor)返回默認的CallAdapterFactory有兩種情況:

  1. callbackExecutor 為空的時候返回的是DefaultCallAdapter.FACTORY,這個DefaultCallAdapter.FACTORY返回一個DefaultCallAdapter,DefaultCallAdapter很簡單,沒做什么處理。
  2. callbackExecutor不為空的時候返回ExecutorCallAdapterFactory,這個Factory返回的CallAdapter是ExecutorCallbackCall,我們看看這個ExecutorCallbackCall的enqueue方法:
@Override public void enqueue(final Callback<T> callback) {
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancelation
                callback.onFailure(new IOException("Canceled"));
              } else {
                callback.onResponse(response);
              }
            }
          });
        }

        @Override public void onFailure(final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(t);
            }
          });
        }
      });
    }

也很簡單,就是修飾了一下CallBack,用callbackExecutor執行真正的回調,這樣回調可以在線程中執行并使用callbackExecutor管理。

如果是Android的話:

 static class Android extends Platform {
    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      if (callbackExecutor == null) {
        callbackExecutor = new MainThreadExecutor();
      }
      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);
      }
    }
  }

也就是說如果在Android上使用的話,如果callbackExecutor為空會直接使用handler將回調返回到主線程(MainThread)。

當然,如果需要自己配置請求Client的話可以設置callFactory。

        HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
        logger.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient
                .Builder()
                .addInterceptor(logger).build();
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com")
                .client(client)
                .build();

使用自己的OkHttpClient,并為這個OkHttpClient設置一個日志工具。通過這種方式設置,整個項目可以共用一個OkHttpClient。

動態代理

 GitHubService service = retrofit.create(GitHubService.class);

create方法傳入一個接口GitHubService,然后動態代理GitHubService。

 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);
            }
            return loadMethodHandler(method).invoke(args);
          }
        });
  }

主要是loadMethodHandler(method).invoke(args)。也就是說在調用service.listRepos方法的時候,會通過loadMethodHandler(method).invoke(args)來執行。那么看看loadMethodHandler做了什么:

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

創建MethodHandler并使用一個Map-methodHandlerCache來自緩存MethodHandler。看來剩下的事交給MethodHandler了。

MethodHandler

  static MethodHandler create(Retrofit retrofit, Method method) {
    CallAdapter<?> callAdapter = createCallAdapter(method, retrofit);
    Type responseType = callAdapter.responseType();
    if (responseType == Response.class || responseType == okhttp3.Response.class) {
      throw Utils.methodError(method, "'"
          + Utils.getRawType(responseType).getName()
          + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    Converter<ResponseBody, ?> responseConverter =
        createResponseConverter(method, retrofit, responseType);
    RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit);
    return new MethodHandler(retrofit.callFactory(), requestFactory, callAdapter,
        responseConverter);
  }
  Object invoke(Object... args) {
    return callAdapter.adapt(
        new OkHttpCall<>(callFactory, requestFactory, args, responseConverter));
  }
  • invoke()方法,調用callAdapter.adapt的方法并傳入一個OkHttpCall。如果是默認的CallAdapter的話返回的就是一個OkHttpCall或者ExecutorCallAdapterFactory.ExecutorCallbackCall,也就是說listRepos("user")方法就返回Call<List<Repo>> 。所以說方法返回什么要看CallAdapter.adapt,如果要返回Observable<List<Repo>>就需要RxJavaCallAdapterFactory.create()的CallAdapter。

  • 在介紹的主要成員的時候說過OkHttpCall,執行請求的類,那么執行請求之前呢。那就要看create方法,這個方法中拿到:

    1. CallAdapter--通過Retrofit類的callAdapter方法獲得。
    2. 拿到ResponseConverter--通過Retrofit類的createResponseConverter方法獲得。
    3. 獲得RequestFactory--通過RequestFactoryParser.parse方法獲得。這個parse方法會解析method也就是listRepos("user")方法的注解和參數,返回一個RequestFactory。
      static RequestFactory parse(Method method, Type responseType, Retrofit retrofit) {
    RequestFactoryParser parser = new RequestFactoryParser(method);
    parser.parseMethodAnnotations(responseType);
    parser.parseParameters(retrofit);
    return parser.toRequestFactory(retrofit.baseUrl());
    }

注:具體的解析就不展開了,主要是將注解和參數的值獲取放入RequestAction,RequestFactory會根據這些RequestAction和基本參數構建OkHttp使用的Request。

  • 最后這些callFactory, requestFactory, responseConverter將傳入OkHttpCall

OkHttpCall

執行Http請求返回數據并解析成實體,在回調中返回。

  • 請求:通過CallFactory(OkHttpClient)的newCall方法傳入一個Request(通過requestFactory.create(args)創建)執行。

    okhttp3.Call rawCall = createRawCall();
    
    private okhttp3.Call createRawCall() throws IOException {
     okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
        if (call == null) {
         throw new NullPointerException("Call.Factory returned null.");
        }
     return call;
    }
    
  • 解析:通過responseConverter.convert()方法解析

    Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ...
    try {
      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;
    }
    }
    

總結

  1. Retrofit就是一個Http請求工具。
  2. Retrofit使用接口代替Java類。
  3. Retrofit通過動態代理,用MethodHandler完成接口方法。
  4. Retrofit的MethodHandler通過RequestFactoryParser.parse解析,獲得接口方法的參數和注解的值,傳入到OkHttpCall,OkHttpCall生成okhttp3.Call完成Http請求并使用Converter解析數據回調。
  5. Retrofit通過工廠設置CallAdapter和Converter,CallAdapter包裝轉換Call,Converter轉換(解析)服務器返回的數據、接口方法的注解參數。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 適配器模式上一篇文章我們已經分析了Retrofit解析注解封裝進ServiceMethod的流程,讀者在這里要記住...
    andcoder閱讀 688評論 0 2
  • 如果你還沒了解Retrofit如何使用,可以先查看這篇文章:Retrofit使用指南 一般分析源碼都習慣從使用開始...
    一只小雞仔閱讀 750評論 1 4
  • Retrofit 源碼解析 簡單用法 Retrofit最簡單的用法就是定義一個接口,創建Retrofit對象,調用...
    Kingty閱讀 813評論 3 14
  • 一、什么是Retrofit A type-safe HTTP client for Android and Jav...
    andcoder閱讀 788評論 2 3
  • 簡介 剛接觸Retrofit的時候,就寫了一篇簡單的使用介紹:Retrofit 2.0基本使用方法,算是對Retr...
    Whyn閱讀 2,887評論 4 24