Retrofit源碼分析三 源碼分析

Retrofit源碼分析三 源碼分析

使用方法

咱們先來看一下Retrofit的常見使用方法:git

//建立網絡請求接口類
public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

//建立Retrofit實例對象
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

//經過動態代理建立網絡接口代理對象
GitHubService service = retrofit.create(GitHubService.class);

//獲取Call對象
Call<List<Repo>> repos = service.listRepos("octocat");

//執行同步請求或異步請求
repos.execute();
repos.enqueue(callback)
複製代碼

上面是Retrofit的最基本使用方法,固然如今使用最多的仍是RxJava2+Retrofit搭配使用,關於RxJava2,你們能夠看個人另外一篇 RxJava2源碼分析 ,固然RxJava2與Retrofit搭配使用的解析我會在稍後分析,這裏咱們先關注最基本的使用方法。github

建立網絡接口類

這一步的目的就是封裝咱們網絡請求相關的一些參數,沒什麼好多說的。設計模式

建立Retrofit實例對象

Retrofit實例對象的建立很明顯是採用了Builder模式,Builder模式在 Java語言中 建立一個 有不少可選配置參數 的對象的時候是很好的一種設計模式。Builder模式有兩個重點,一個是在 Java語言中 中,另外一個是 有不少可選配置參數,其實在如今的Android開發中,使用Kotlin開發Android已經很廣泛了,熟悉Kotlin語法的小夥伴可能很熟悉了,因爲Kotlin中 默認參數 的存在,因此在Kotlin中使用Builder模式的意義不大。但因爲Java語法的限制,在建立一個 有不少可選配置參數 的時候,Builder模式仍是首要選擇。api

咱們來看一下Retrofit中的成員變量:緩存

public final class Retrofit {
  //緩存封裝好的ServiceMethod
  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
  //OKHttp中的網絡請求工廠
  final okhttp3.Call.Factory callFactory;
  //BaseUrl
  final HttpUrl baseUrl;
  //數據轉換器工廠集合
  final List<Converter.Factory> converterFactories;
  //網絡請求適配器工廠集合
  final List<CallAdapter.Factory> callAdapterFactories;
  //處理線程切換
  final @Nullable Executor callbackExecutor;
  //不須要關注,默認爲false
  final boolean validateEagerly;
  
  //忽略無關代碼......
  }
複製代碼

serviceMethodCache 是一個HashMap,它的Key是Method,表明咱們定義的網絡請求接口類中的方法,它的Value是ServiceMethod,表明對網絡請求接口類中的方法的一個封裝,簡單看一下它就明白了:bash

final class ServiceMethod<R, T> {

  private final okhttp3.Call.Factory callFactory;
  private final CallAdapter<R, T> callAdapter;

  private final HttpUrl baseUrl;
  private final Converter<ResponseBody, R> responseConverter;
  private final String httpMethod;
  private final String relativeUrl;
  private final Headers headers;
  private final MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;
  
  //忽略無關代碼.......
  }
複製代碼

很明顯了,ServiceMethod就是對網絡請求參數的封裝類,包含請求頭、相對url、GET請求或者是POST請求等等對請求的配置信息。serviceMethodCache 就是一個對ServiceMethod的緩存,能夠提升必定的效率。網絡

在Retrofit中,默認的數據轉換器工廠就是 GsonConverterFactory ,因此其實若是咱們是使用 Gson 來作數據轉換的,其實沒有必要去配置。在Android平臺,Retrofit中默認的網絡請求適配器工廠是 ExecutorCallAdapterFactory ,咱們簡單瞅一眼它是如何被建立的:框架

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 {
      //注意這裏建立了一個位於主線程的Handler
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        //經過handler.post(runnable)實現線程切換
        handler.post(r);
      }
    }
  }
複製代碼

能夠看到,在建立 ExecutorCallAdapterFactory 的同時傳入了一個 callbackExecutor ,這個 callbackExecutor 也是Retrofit中默認的 callbackExecutor ,在Android平臺中它是 MainThreadExecutor類型 ,能夠看到,在它的內部建立了一個位於主線程的Handler。咱們知道,使用Retrofit的時候不一樣於直接使用OKHttp,在使用Retrofit的異步網絡請求時,網絡結果的回調是位於主線程中的,那麼Retrofit是如何切換的線程,看過上面的代碼應該會內心有個數了,它是經過 handler.post(r) 來實現由子線程到主線程的切換。異步

經過動態代理建立網絡接口代理對象

看過個人Retrofit源碼分析第二篇:代理模式的小夥伴們應該都比較清楚了,在Retrofit的 create 方法中實際上是使用了動態代理生成了一個代理對象,如今咱們就來看一下 create 的源碼:ide

public <T> T create(final Class<T> service) {
    //忽略無關代碼......
    
    //下面就是JDK給咱們提供的動態代理了
    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 {
            //忽略無關代碼......
            
            //獲取method的網絡請求參數的封裝類ServiceMethod對象
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
                
            //獲取對OKHttp中的RealCall的一個包裝類OkHttpCall對象
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //經過網絡請求適配器將原始的Call對象轉換成須要的對象,好比RxJavaCallAdapter會將Call對象轉換成Observable。
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }
複製代碼

create 方法中作了3件事:

  • 封裝網絡請求方法
  • 封裝原始Call對象
  • 經過CallAdapter轉換Call對象 封裝網絡請求方法很容易理解,關於ServiceMethod上面已經說過,再也不贅述。封裝原始Call對象,對OKHttp源碼熟悉的小夥伴應該知道,原始的Call其實就是OkHttp中的ReallCall。若是不熟悉OkHttp的同窗能夠看我以前的一篇 OkHttp源碼分析 。咱們能夠簡單看一下這個包裝類 OkHttpCall :
final class OkHttpCall<T> implements Call<T> {

    //忽略無關代碼......    
    
    @Override public Response<T> execute() throws IOException {
    okhttp3.Call call;

    //熟悉OkHttp源碼的同窗應該很熟悉了,徹底照抄OkHttp中的代碼,確保每一個Call只會被執行一次
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      //忽略無關代碼......
    
      call = rawCall;
      if (call == null) {
        try {
          //建立OkHttp中的RealCall對象
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException | Error e) {
          throwIfFatal(e); //  Do not assign a fatal error to creationFailure.
          creationFailure = e;
          throw e;
        }
      }
    }

    if (canceled) {
      call.cancel();
    }
    //解析OkHttp中的RealCall執行同步方法後返回的網絡數據
    return parseResponse(call.execute());
  }
  
  
  @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");

    okhttp3.Call call;
    Throwable failure;

    //確保一個Call對象只被執行一次
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          //建立OkHttp中的RealCall對象
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }
    
    //調用OkHttp中的RealCall的異步請求網絡方法
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }
}
複製代碼

能夠看到,Retrofit中的這個 OKHttpCall 徹底是對OkHttp中的 RealCall 的一個包裝。在 OKHttpCall 中的同步網絡方法 execute 和異步網絡方法 enQueue 中其實就作了三件事:獲取 RealCall 對象,調用 RealCall 中的 execute 或者 enQueue 方法,而後去解析OkHttp返回的原始數據並轉換成咱們須要的類型,就這麼簡單。

接下來就 create 方法中就只剩下 經過CallAdapter轉換Call對象 了,咱們上面說過,在沒有特別配置CallAdapter的時候,默認的CallAdapterFactory是 ExecutorCallAdapterFactory ,很明顯,CallAdapter是由Factory建立的,那咱們看一下這個默認的CallAdapterFactory:

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
    
  //本質是傳入的MainThreadExecutor
  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);
    
    //直接建立並返回一個CallAdapter的匿名對象
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        //返回默認的CallAdapter轉換後的Call對象
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

  static final class ExecutorCallbackCall<T> implements Call<T> {
    //本質是傳入的MainThreadExecutor
    final Executor callbackExecutor;
    //就是OKHttpCall,從名字也能理解,代理Call對象
    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");

       //調用OkHttp中RealCall的異步網絡請求
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
            //注意,OkHttp的異步回調是在子線程的,Retrofit這裏實現了線程的切換,本質是調用了handler.post(runnable)
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
            //注意,OkHttp的異步回調是在子線程的,Retrofit這裏實現了線程的切換,本質是調用了handler.post(runnable)
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

    @Override public boolean isExecuted() {
      return delegate.isExecuted();
    }

    @Override public Response<T> execute() throws IOException {
       //因爲同步方法不須要切線程,因此直接執行並返回OKHttpCall的同步網絡方法
      return delegate.execute();
    }

    @Override public void cancel() {
      delegate.cancel();
    }

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

    @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
    @Override public Call<T> clone() {
      return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
    }

    @Override public Request request() {
      return delegate.request();
    }
  }
}
複製代碼

上面的代碼其實也很清晰了 ExecutorCallAdapterFactory 這個CallAdapter工廠類直接建立並返回一個CallAdapter的匿名對象,這個其實就是咱們Retrofit的默認CallAdapter,關鍵是這個CallAdapter的adapt方法,它返回了 ExecutorCallbackCall 這個對OkHttpCall的包裝類,咱們關注這個包裝類的 enqueue 方法,在這個方法中,它經過調用 callbackExecutor.execute 來實現了子線程到主線程的線程切換。這個 callbackExecutor 就是 MainThreadExecutor ,這個類咱們上面提到過, MainThreadExecutor 中的 execute 方法內部就是 handler.post(r); ,這個 handler 其實就是主線程的,所以實現了線程切換。

獲取Call對象並執行同步或異步方法

其實通過上一步的分析,咱們已經知道了,咱們獲取的Call對象,實際上是經過動態代理中 serviceMethod.adapt(okHttpCall) 返回的Call對象,這個其實就是 ExecutorCallbackCall ,這個咱們都很清楚了,它是對OkHttp中RealCall的一個包裝類,在它的異步方法中經過調用 callbackExecutor.execute 實現了線程的切換,固然本質仍是經過 Handler 機制。

其實到此爲止,基本的流程已經分析完畢了,咱們到這裏也會很清楚Retrofit的定位:Retrofit並非一個網絡請求的框架,而是一封裝網絡請求參數,解析網絡返回結果的框架。下面咱們來分析一下使用了RxJava2CallAdapter的狀況。

RxJava2CallAdapter的原理

CallAdapter的重點是它的adapt方法,咱們來看一下RxJava2CallAdapter中的adapt方法:

@Override public <R> Object adapt(Call<R> call) {
    //建立一個發射網絡返回結果的Observable
    Observable<Response<R>> responseObservable = new CallObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }
    
    //默認scheduler爲空
    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }
複製代碼

這段代碼本質是建立一個發射網絡返回結果的Observable,咱們看一下 CallObservable 的內部實現,看過RxJava2源碼的同窗應該都知道,Observable的關鍵方法是 subscribeActual,咱們就看一下這個方法內部都作了什麼:

@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();
    observer.onSubscribe(new CallDisposable(call));

    boolean terminated = false;
    try {
      //調用了OKHttpCall的同步網絡訪問方法,並獲取網絡數據
      Response<T> response = call.execute();
      if (!call.isCanceled()) {
        //將獲取到的網絡數據發送到觀察者observer
        observer.onNext(response);
      }
      if (!call.isCanceled()) {
        terminated = true;
        //發送結束事件
        observer.onComplete();
      }
    } catch (Throwable t) {
      Exceptions.throwIfFatal(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));
        }
      }
    }
  }
複製代碼

熟悉RxJava2的同窗看完就應該懂了:RxJava2CallAdapter經過adapt方法生成並返回一個 CallObservable 對象,在這個 CallObservable 內部通調用 OKHttpCallexecute() 方法進行網絡訪問,並將獲取到的數據發送到下一級的觀察者observer中。

到此爲止,Retrofit的源碼分析終於結束了,其實它並不難,但想要徹底理解整個網絡訪問流程,除了要明白Retrofit,還須要瞭解OKHttp甚至是RxJava,對後二者不太熟悉的小夥伴們能夠看個人另外兩篇源碼分析:OkHttp源碼分析RxJava2源碼分析 ,在熟悉了OKHttp和RxJava2的基礎上再回過頭來看Retrofit,相信你會有更深的理解。

相關文章
相關標籤/搜索