Retrofit 是如何工作的?

bluesky5566 7年前發布 | 16K 次閱讀 Retrofit Java

Retrofit是如何工作的?

注:本文基于 Retrofit2.0版本,并配合 RxJava 來分析。

com.squareup.retrofit2:retrofit:2.0.0

com.squareup.retrofit2:converter-gson:2.0.0

com.squareup.retrofit2:adapter-rxjava:2.0.0

?

? Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to how requests are made.

本文主要通過分析 Retrofit 與 RxJava 的合作流程 來深入理解 Retrofit的工作原理,并且解答自己心中的疑惑。

疑惑

  1. 我們調用接口的方法后是怎么發送請求的?這背后發生了什么?
  2. Retrofit 與 OkHttp 是怎么合作的?
  3. Retrofit 中的數據究竟是怎么處理的?它是怎么返回 RxJava.Observable 的?

Retrofit 的基本使用

public interface ApiService{
  @GET("data/Android/"+ GankConfig.PAGE_COUNT+"/{page}")
    Observable<GankResponse> getAndroid(@Path("page") int page);
}

// Builder 模式來構建 retrofit Retrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create())) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .client(okHttpClient) .build(); // 通過 retrofit.create 方法來生成 service(非四大組件中的 Service) ApiService service = retrofit.create(ApiService.class); // 發起請求 獲取數據 Observable<GankResponse> observable= service.getAndroid(1); observable....</code></pre>

Retrofit 就這樣經過簡單的配置后就可以向服務器請求數據了,超級簡單。

Retrofit.create 方法分析

Retrofit的 create 方法作為 Retrofit 的入口,當然得第一個分析。

public <T> T create(final Class<T> service) {
    //驗證接口是否合理
    Utils.validateServiceInterface(service);
    //默認 false
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    // 動態代理
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          // 平臺的抽象,指定默認的 CallbackExecutor CallAdapterFactory用,  這里 Android 平臺是 Android (Java8 iOS 咱不管)
          private final Platform platform = Platform.get();
          //ApiService 中的方法調用都會走到這里
          @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.
            // 注釋已經說明 Object 的方法不管
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            // java8 的默認方法,Android暫不支持默認方法,所以暫時也不需要管
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            // 重點了 后面分析
            // 為 Method 生成一個 ServiceMethod
            ServiceMethod serviceMethod = loadServiceMethod(method);
            // 再包裝成 OkHttpCall
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);      // 請求
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

在上面的代碼中可以看到,Retrofit 的主要原理是利用了 Java 的 動態代理技術 ,把 ApiService 的方法調用集中到了 InvocationHandler.invoke ,再構建了ServiceMethod ,OKHttpCall,返回 callAdapter.adapt 的結果。

要弄清楚,還需要分析那最后三行代碼。

一步一步來。

ServiceMethod的職責以及 loadServiceMethod分析

我認為 ServiceMethod 是接口 具體方法的抽象 ,它主要負責解析它對應的 method 的各種參數(它有各種如 parseHeaders 的方法),比如注解(@Get),入參,另外還負責獲取 callAdapter,responseConverter等Retrofit配置,好為后面的 okhttp3.Request 做好參數準備,它的 toRequest 為 OkHttp 提供 Request,可以說它承載了后續 Http 請求所需的一切參數。

再分析 loadServiceMethod ,比較簡單。

// serviceMethodCache 的定義
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
 // 獲取method對應的 ServiceMethod
 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;
  }

loadServiceMethod 方法,負責 為 method 生成一個 ServiceMethod ,并且給 ServiceMethod 做了緩存。

動態代理是有一定的性能損耗的,并且ServiceMethod 的創建伴隨著各種注解參數解析,這也是耗時間的,在加上一個 App 調用接口是非常頻繁的,如果每次接口請求都需要重新生成那么有浪費資源損害性能的可能,所以這里做了一份緩存來提高效率。

OkHttpCall

再接下去往后看 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); ,是再為 ServiceMethod 以及 args(參數)生成了一個 OkHttpCall 。

從 OkHttpCall 這個名字來看就能猜到,它是對 OkHttp3.Call 的組合包裝,事實上,它也確實是。( OkHttpCall 中有一個成員 okhttp3.Call rawCall )。

callAdapter.adapt流程分析

最后 return serviceMethod.callAdapter.adapt(okHttpCall) 似乎是走到了最后一步。

如果說前面的都是準備的話,那么到這里就是真的要行動了。

來分析一下,這里涉及到的 callAdapter ,是由我們配置 Retrofit 的 addCallAdapterFactory 方法中傳入的 RxJavaCallAdapterFactory.create() 生成,實例為 RxJavaCallAdapterFactory 。

實例的生成大致流程為:

ServiceMethod.Bulider.Build()

->ServiceMethod.createCallAdapter()

->retrofit.callAdapter()

->adapterFactories遍歷

? ->最終到RxJavaCallAdapterFactory.get()#getCallAdapter()

? ->return return new SimpleCallAdapter(observableType, scheduler);

由于使用了 RxJava ,我們最終得到的 callAdapter 為 SimpleCallAdapter ,所以接下去分析 SimpleCallAdapter 的 adapt 方法:

這里涉及到的 CallOnSubscriber 后面有給出:

@Override public <R> Observable<R> adapt(Call<R> call) {
      // 這里的 call 是 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args) 生成的 okHttpCall
      Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) //
          .flatMap(new Func1<Response<R>, Observable<R>>() {
            @Override public Observable<R> call(Response<R> response) {
              if (response.isSuccessful()) {
                return Observable.just(response.body());
              }
              return Observable.error(new HttpException(response));
            }
          });
      if (scheduler != null) {
        return observable.subscribeOn(scheduler);
      }
      return observable;
    }
  }
static final class CallOnSubscribe<T> implements Observable.OnSubscribe<Response<T>> {
    private final Call<T> originalCall;

CallOnSubscribe(Call<T> originalCall) {
  this.originalCall = originalCall;
}

@Override public void call(final Subscriber<? super Response<T>> subscriber) {
  // Since Call is a one-shot type, clone it for each new subscriber.
  final Call<T> call = originalCall.clone();
  // Attempt to cancel the call if it is still in-flight on unsubscription.
  // 當我們取消訂閱的時候 會取消請求 棒棒噠
  subscriber.add(Subscriptions.create(new Action0() {
    @Override public void call() {
      call.cancel();
    }
  }));

  try {
    // call 是 OkHttpCall 的實例
    Response<T> response = call.execute();
    if (!subscriber.isUnsubscribed()) {
      subscriber.onNext(response);
    }
  } catch (Throwable t) {
    Exceptions.throwIfFatal(t);
    if (!subscriber.isUnsubscribed()) {
      subscriber.onError(t);
    }
    return;
  }

  if (!subscriber.isUnsubscribed()) {
    subscriber.onCompleted();
  }
}

}</code></pre>

SimpleCallAdapter.adapt 很簡單,創建一個 Observable獲取CallOnSubscribe中的Response 通過 flatMap轉成Observable后返回。這里去發送請求獲取數據的任務在CallOnSubscribe.call 方法之中。并且最后走到了 okHttpCall.execute 中去了。

// OkHttpCall.execute

@Override public Response<T> execute() throws IOException { okhttp3.Call call;

synchronized (this) {
  //同一個請求 不能執行兩次
  if (executed) throw new IllegalStateException("Already executed.");
  executed = true;
 // ...省略 Execption 處理

  call = rawCall;
  if (call == null) {
    try {
      // 創建 okhttp3.call 
      call = rawCall = createRawCall();
    } catch (IOException | RuntimeException e) {
      creationFailure = e;
      throw e;
    }
  }
}
if (canceled) {
  call.cancel();
}
// 請求并解析response 這個 call 是 okhttp3.call 是真交給 OkHttp 去發送請求了 
return parseResponse(call.execute());

}

// 解析 response Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { //... 省略一些處理 只顯示關鍵代碼 try { T body = serviceMethod.toResponse(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { catchingBody.throwIfCaught(); throw e; } }

// serviceMethod.toResponse T toResponse(ResponseBody body) throws IOException { // 還記得嗎?這就是我們配置Retrofit時候的 converter return responseConverter.convert(body); }</code></pre>

經過一連串的處理,最終在 OkHttpCall.execute() 的方法中生成 okhttp3.call 交給 OkHttpClient 去發送請求,再由我們配置的 Converter(本文為GsonConverterFactory) 處理 Response,返回給SimpleCallAdapter處理,返回我們最終所需要的Observable。

流程分析流程圖總結

總體的流程圖整理如下:

解答疑問

對于之前的疑問可以作答了。

第一個疑問: 我們調用接口的方法后是怎么發送請求的?這背后發生了什么?

Retrofit 使用了動態代理給我們定義的接口設置了代理,當我們調用接口的方法時,Retrofit 會攔截下來,然后經過一系列處理,比如解析方法的注解等,生成了 Call Request 等OKHttp所需的資源,最后交給 OkHttp 去發送請求, 此間經過 callAdapter,convertr 的處理,最后拿到我們所需要的數據。

第二個疑問: Retrofit 與 OkHttp 是怎么合作的?

在Retrofit 中,ServiceMethod 承載了一個 Http 請求的所有參數,OkHttpCall 為 okhttp3.call 的組合包裝,由它們倆合作,生成用于 OkHttp所需的 Request以及okhttp3.Call,交給 OkHttp 去發送請求。(在本文環境下具體用的是 call.execute() )

可以說 Retrofit 為 OkHttp 再封裝了一層,并增添了不少功能以及擴展,減少了開發使用成本。

第三個疑問: Retrofit 中的數據究竟是怎么處理的?它是怎么返回 RxJava.Observable 的?

Retrofit 中的數據其實是交給了 callAdapter 以及 converter 去處理,callAdapter 負責把 okHttpCall 轉成我們所需的 Observable類型(本文環境),converter負責把服務器返回的數據轉成具體的實體類。

小結

Retrofit 的源碼其實非常好跟也非常好理解,不像看 framework 的代碼,跟著跟著就不見了。

另外 Retrofit的代碼確實非常漂亮,將設計模式運用的可以說是爐火純青,非常值得學習。

 

 

來自:https://github.com/RTFSC-Android/RTFSC/blob/master/libraries/retrofit/how-retrofit-works.md

 

 本文由用戶 bluesky5566 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!