【Retrofit2進(jìn)階】---從源碼角度看Retrofit2實(shí)現(xiàn)原理

前言

本文是Retrofit2進(jìn)階系列的第一篇---從源碼角度看Retrofit2實(shí)現(xiàn)原理,我會盡可能用簡潔的代碼幫大家理解Retrofit實(shí)現(xiàn)一次網(wǎng)絡(luò)請求的核心流程是怎樣的,這個流程整體上就4個步驟,是不復(fù)雜的,希望大家?guī)е判淖x下去,在文章末尾,我也為大家做出了簡單的總結(jié),希望能幫大家更好的理解這個框架,希望在讀文章的你能有一些收獲,能有更大的進(jìn)步。備注:基于Retrofit2.4.0分析

系列文章:
Retrofit2進(jìn)階】---啟示、思想

先來看一個最基礎(chǔ)的網(wǎng)絡(luò)請求案例:

//1、創(chuàng)建Retrofit接口
public interface ApiService {
    @GET("/")
    Observable<String> getData();
    @GET("/")
    Call<String> getData2();
}

//2、retrofit相關(guān)配置 
Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://xxxx/")
                    .client(client)
                    //json轉(zhuǎn)換
                    .addConverterFactory(GsonConverterFactory.create())
                    //RxJava2轉(zhuǎn)換器
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
//創(chuàng)建接口對象
ApiService apiService = retrofit.create(ApiService.class);

//3、接口方法調(diào)用
3.1 call調(diào)用
apiService.getData2().enqueue();

3.2結(jié)合rxjava調(diào)用
apiService.getData().subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe();

下面就來分析一下Retrofit2是如何完成一次完整的網(wǎng)絡(luò)請求的。

先來看一下Call調(diào)用

public interface ApiService {
    @GET("/")
    Call<String> getData2();
}

通過接口調(diào)用會返回一個Call對象,如果你看過OkHttp源碼的話,應(yīng)該會對這個Call很熟悉,它封裝了一個網(wǎng)絡(luò)請求的任務(wù),但是它卻不做網(wǎng)絡(luò)請求,而是通過調(diào)用enqueue()或者execute()來發(fā)起真正的網(wǎng)絡(luò)請求。

那這個Call對象如何生成的?其實(shí)可以在retrofit.create()方法中找到答案。

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

create()內(nèi)部的核心就一件事情,通過動態(tài)代理生成一個代理類對象,具體來說就是通過Proxy.newProxyInstance()來創(chuàng)建的。然后在回調(diào)方法invoke()內(nèi)部通過一系列解析,包裝,最終返回用于發(fā)起網(wǎng)絡(luò)請求的Call對象或者用于結(jié)合rxjava使用的Observable對象。

這里的關(guān)鍵點(diǎn)與難點(diǎn)在于,你要懂代理模式和動態(tài)代理,如果你還不會的話,建議先簡單學(xué)習(xí)一下再接著往下看,不然很多邏輯的連貫性你是不懂的。這里推薦一下我之前的一篇文章Java動態(tài)代理那些你容易忽略的細(xì)節(jié)。

先說一下Retrofit2動態(tài)代理的邏輯

//retrofit的API接口對象
ApiService apiService;
//創(chuàng)建代理對象
 apiService = retrofit.create(ApiService.class);
//調(diào)用代理類中的方法
apiService.xxx();

首先生成一個代理類對象,當(dāng)調(diào)用代理類的方法時,會回調(diào)執(zhí)行InvocationHandlerinvoke()方法

@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            //省略,不會執(zhí)行的代碼

            //生成Call關(guān)鍵在這里
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  • ServiceMethod是對接口中的方法進(jìn)行解析,包括注解、參數(shù),生成Http Request,具體來說是toRequest(),將response轉(zhuǎn)換為String或者實(shí)體類,具體說是toResponse();
  • OkHttpCall是對okhttp3.call的封裝,以及okhttp3的其他方法的調(diào)用;
  • serviceMethod.callAdapter.adapt(okHttpCall);通過calladapter轉(zhuǎn)換器,將 okhttp3.call轉(zhuǎn)換成可以用于發(fā)起網(wǎng)絡(luò)請求的retrofit2.Call或者說用于rxjava的Observable

下面對ServiceMethod、 OkHttpCall 、CallAdapter做一個簡單的解釋,注意不是詳解,這樣可以讓你避免陷入一葉障目的困境。我們先搞清楚主流程,那些細(xì)枝末節(jié)后面再看唄。

1、ServiceMethod
它是通過建造者模式來創(chuàng)建的,核心內(nèi)容如下:
這部分內(nèi)容先不用詳細(xì)理解,可以先看個大概,后面再單獨(dú)來看

 public ServiceMethod build() {
        //獲取具體的網(wǎng)絡(luò)適配器對象CallAdapter,如果retrofit配置了rxjava2轉(zhuǎn)換器,那這里就是RxJava2CallAdapter
       callAdapter = createCallAdapter();
        
       responseType = callAdapter.responseType();
      //獲取響應(yīng)轉(zhuǎn)換器
     responseConverter = createResponseConverter();

      //解析方法注解,比如@GET、@POST、@FormUrlEncoded等等
      //這里解析完畢之后可以獲取到Http請求方式,請求體,url等信息
      for (Annotation annotation : methodAnnotations) {
            parseMethodAnnotation(annotation);
      }

      //解析當(dāng)前方法的參數(shù)
int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        if (Utils.hasUnresolvableType(parameterType)) {
          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

}

2、OkHttpCall
它繼承于Retrofit2.Call,內(nèi)部就是對okhttp3一系列操作的封裝,甚至說代碼都是直接copy的。這里就不展開詳細(xì)解釋了。注意:不要被OkHttpCall的名字所迷惑,它不是okhttp3中的call,而是Retrofit2.Call

final class OkHttpCall<T> implements Call<T> {
  private final ServiceMethod<T, ?> serviceMethod;
  private final @Nullable Object[] args;

  private volatile boolean canceled;

  @GuardedBy("this")
  private @Nullable okhttp3.Call rawCall;
  @GuardedBy("this")
  private @Nullable Throwable creationFailure; // Either a RuntimeException or IOException.
  @GuardedBy("this")
  private boolean executed;

  OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }

3、callAdapter
上面invoke()方法中,最后一步是return serviceMethod.callAdapter.adapt(okHttpCall);,
上面有提到過,這一步的作用是返回一個Retrofit2.Call或者Observable。

這里的CallAdapter對象是一個接口對象,所以需要找到他的實(shí)現(xiàn)類。先回顧一下在Retrofit配置的時候,有這么一行代碼.addCallAdapterFactory(RxJava2CallAdapterFactory.create()),它可以將接口方法返回Observable,如果不加這個配置,會如何呢?答案是會返回Retrofit2.Call類型,具體是如何產(chǎn)生的,請看如下流程:

retrofit.build()---->platform.defaultCallAdapterFactory()--->Platform.ExecutorCallAdapterFactory--->ExecutorCallAdapterFactory.ExecutorCallbackCall

3.1 Retrofit沒有配置callAdapter時
serviceMethod.callAdapter就是ExecutorCallAdapterFactory.get()返回的CallAdapter實(shí)例,然后調(diào)用它的adapt會返回一個ExecutorCallbackCall對象。簡單看一下這個對象,它是繼承于Call的。

static final class ExecutorCallbackCall<T> implements Call<T> {

3.2 Retrofit配置了RxJava2CallAdapterFactory時
serviceMethod.callAdapter就是RxJava2CallAdapter,調(diào)用它的adapt會返回一個Observable對象。

到這里就搞清楚了生成Retrofit2.Call或者Observable的整個流程,最后就只剩下一步了,發(fā)起網(wǎng)絡(luò)請求和響應(yīng)是如何實(shí)現(xiàn)的。

4、網(wǎng)絡(luò)請求的實(shí)現(xiàn)
4.1 Call實(shí)現(xiàn)網(wǎng)絡(luò)請求
上面提到過Call對象是通過enqueue()或者execute()發(fā)起網(wǎng)絡(luò)請求的,而這個Call對象實(shí)際上是ExecutorCallbackCall的實(shí)例

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, 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 cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } 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);
            }
          });
        }
      });
    }

所以,當(dāng)我們外部調(diào)用enqueue()時,實(shí)際調(diào)用的就是ExecutorCallbackCall.enqueue(),而這里的delegateOkHttpCall,所以最終會由OkHttpCall內(nèi)部的okhttp3去執(zhí)行。

這里還有一個關(guān)鍵點(diǎn)callbackExecutor,它的來源如下:

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

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }

可以看到enqueue的回調(diào)結(jié)果是在主線程中。

4.2 Observable實(shí)現(xiàn)網(wǎng)絡(luò)請求
從之前的分析中,我們可以知道Observable是在RxJava2CallAdapter內(nèi)部的adapt()方法返回的:

@Override public Object adapt(Call<R> call) {
    //創(chuàng)建一個發(fā)射網(wǎng)絡(luò)返回數(shù)據(jù)的Observable
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

    //這里為null
    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    //可以轉(zhuǎn)換成Flowable
    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }

關(guān)鍵點(diǎn)在第一行代碼,isAsync返回true,所以看一下CallEnqueueObservable的實(shí)現(xiàn)


final class CallEnqueueObservable<T> extends Observable<Response<T>> {
  private final Call<T> originalCall;

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

  @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    Call<T> call = originalCall.clone();
    CallCallback<T> callback = new CallCallback<>(call, observer);
    observer.onSubscribe(callback);
    call.enqueue(callback);
  }

如果你看過RxJava2的源碼的話,應(yīng)該對這段代碼非常熟悉,每個Observable都會去調(diào)用subscribeActual()方法。這里通過call.enqueue()去發(fā)起網(wǎng)絡(luò)請求,然后通過CallCallback回調(diào)

private static final class CallCallback<T> implements Disposable, Callback<T> {
    private final Call<?> call;
    private final Observer<? super Response<T>> observer;
    boolean terminated = false;

    CallCallback(Call<?> call, Observer<? super Response<T>> observer) {
      this.call = call;
      this.observer = observer;
    }

    @Override public void onResponse(Call<T> call, Response<T> response) {
      if (call.isCanceled()) return;

      try {
        observer.onNext(response);

        if (!call.isCanceled()) {
          terminated = true;
          observer.onComplete();
        }
      } catch (Throwable t) {
        if (terminated) {
          RxJavaPlugins.onError(t);
        } else if (!call.isCanceled()) {
          try {
            observer.onError(t);
          } catch (Throwable inner) {
            Exceptions.throwIfFatal(inner);
            RxJavaPlugins.onError(new CompositeException(t, inner));
          }
        }
      }
    }

    @Override public void onFailure(Call<T> call, Throwable t) {
      if (call.isCanceled()) return;

      try {
        observer.onError(t);
      } catch (Throwable inner) {
        Exceptions.throwIfFatal(inner);
        RxJavaPlugins.onError(new CompositeException(t, inner));
      }
    }

    @Override public void dispose() {
      call.cancel();
    }

    @Override public boolean isDisposed() {
      return call.isCanceled();
    }
  }
}

這里的邏輯也很簡單,就是把網(wǎng)絡(luò)請求的結(jié)果發(fā)射出去。

到這里,Retrofit2網(wǎng)絡(luò)執(zhí)行流程的源碼分析就算完了。其實(shí)這里的類不算多,邏輯上也比較清晰,但是需要掌握的知識點(diǎn)比較雜,比如入口處的動態(tài)代理,中間的OkHttpRxJava2源碼。所以,這里建議基礎(chǔ)薄弱的同學(xué),看完這些內(nèi)容之后再回頭來看Retrofit2,理解會更加深刻。


總結(jié)

流程
1、通過建造者模式創(chuàng)建一個Retrofit實(shí)例,也就是做Retrofit相關(guān)配置;
2、通過Retrofit對象的creat()方法創(chuàng)建一個代理對象,當(dāng)調(diào)用接口方法時,都會調(diào)用動態(tài)代理的invoke()方法;
3、invoke()內(nèi)部做了3件事情:

  • 3.1 會對method進(jìn)行解析,最后生成ServiceMethod對象,并緩存起來,下次調(diào)用就不需要解析了;
  • 3.2 將原始的okhttp3.call封裝成OkHttpCall
  • 3.3 通過CallAdapter轉(zhuǎn)換成Call對象或者Observable對象

4、如果返回Call對象,調(diào)用execute或者enqueue方法去做網(wǎng)絡(luò)請求;如果返回Observable對象,則結(jié)合rxjava2做后續(xù)的操作。

結(jié)論:

  • Retrofit是一個封裝了網(wǎng)絡(luò)請求的框架,它本身是不做網(wǎng)絡(luò)請求的,而是通過Okhttp實(shí)現(xiàn)的;

  • Retrofit提供了一種更簡潔的發(fā)起網(wǎng)絡(luò)請求的方式,具體來說是通過接口和注解的方式來簡化網(wǎng)絡(luò)請求相關(guān)的一系列配置;

  • 可擴(kuò)展性。比如說Client、數(shù)據(jù)轉(zhuǎn)換Gson、RxJava適配等。

推薦文章:
Retrofit分析-經(jīng)典設(shè)計(jì)模式案例

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容