ServiceMethod

ServiceMethod

ServiceMethod時Retrofit中的核心類,之前說的Call捣鲸,CallAdapter.Factory和Convert.Factory纤怒,RequestFactory,Call.Factory都是在ServiceMethod里面的到體現(xiàn)嘹黔。
ServiceMethod是個抽象類,子類類有抽象類HttpServiceMethod涂身,CallAdapted雄卷,SuspendForResponse,SuspendForBody蛤售。具體來看下ServiceMethod和HttpServiceMethod

abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
     //根據(jù)retrofit對象和mathod得到RequestFactory
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

     //調(diào)用HttpServiceMethod.parseAnnotations()得到ServiceMethod最終的實現(xiàn)類
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

  abstract @Nullable T invoke(Object[] args);
}

  1. 根據(jù)retrofit和method得到RequesrFactory
  2. 調(diào)用HttpServiceMethod.parseAnnotations()

下面再看下HttpServiceMethod

  //解析接口方法上的注釋丁鹉,構(gòu)造出一個可重用的ServiceMethod來用于Http請求
  //因為構(gòu)造HttpServiceMethod中需要反射,因此最好每個請求方法只構(gòu)建一次并且可以復用它
  //重點是HttpServiceMethod對于每一個請求方法悴能,只構(gòu)建一次揣钦,再次請求相同的方法直接復用之前創(chuàng)建的
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
      Type[] parameterTypes = method.getGenericParameterTypes();
      Type responseType = Utils.getParameterLowerBound(0,
          (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response<T>.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      } else {
        // TODO figure out if type is nullable or not
        // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
        // Find the entry for method
        // Determine if return type is nullable or not
      }

      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      adapterType = method.getGenericReturnType();
    }

     //構(gòu)造出相應的CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    if (responseType == okhttp3.Response.class) {
      throw methodError(method, "'"
          + getRawType(responseType).getName()
          + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }
    // TODO support Unit for Kotlin?
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }
     //構(gòu)造出相應的responseConverter
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
     //構(gòu)造出相應的okhttp3.Call.Factory
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
          continuationBodyNullable);
    }
  }
  1. 根據(jù)retrofit上存在的CallAdapter.Factory列表,請求方法method搜骡,方法返回值的類型adapterType拂盯,注解annotations構(gòu)造出相應的CallAdapter
  2. 根據(jù)retrofit,method记靡,responseType構(gòu)造出responseConverter
  3. 得到retrofit.callFactory作為自己的callFactory

上面主要是創(chuàng)建請求適配器谈竿,和返回數(shù)據(jù)轉(zhuǎn)換器团驱,我們詳細解析下請求適配器CallAdapter的創(chuàng)建過程,responseConvert的創(chuàng)建跟CallAdapter類似

  //調(diào)用retrofit.callAdapter(returnType, annotations)
  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
    try {
      //noinspection unchecked
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create call adapter for %s", returnType);
    }
  }



  
   //根據(jù)請求方法的返回類型空凸,返回相應的CallAdapter嚎花,如果沒有合適的CallAdapter,那么就拋異常
  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");
    
     //因為skipPast為null呀洲,所以初始時start = 0
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
        //查找是否有匹配對應返回值的CallAdapter紊选,這里就調(diào)用到CallAdapterFactory中去了
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

     //如果沒有合適的CallAdapter,那么拋出異常
    StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
        .append(returnType)
        .append(".\n");
    if (skipPast != null) {
      builder.append("  Skipped:");
      for (int i = 0; i < start; i++) {
        builder.append("\n   * ").append(callAdapterFactories.get(i).getClass().getName());
      }
      builder.append('\n');
    }
    builder.append("  Tried:");
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      builder.append("\n   * ").append(callAdapterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
  }

  1. 從頭遍歷CallAdapterFactory的列表道逗,找到符合請求返回值的請求適配器CallAdapter兵罢。如果請求的返回值為Observable,那么相應的CallAdapter就是RxJava2CallAdapter滓窍,如果請求返回值為Call卖词,那么就是默認CallAdapter

整體請求流程

前面一篇文章和上面對于ServiceMethod的分析,已經(jīng)對于Retrofit的關(guān)鍵類的作用有了了解吏夯,下面就結(jié)合具體的請求流程此蜈,把上面的類都串起來分析。

Retrofit時采用構(gòu)建者模式構(gòu)造的

  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();//緩存ServiceMethod的表

  final okhttp3.Call.Factory callFactory;//請求的構(gòu)造工廠噪生,就是OkHttpClient
  final HttpUrl baseUrl;//基礎Url
  final List<Converter.Factory> converterFactories;//數(shù)據(jù)轉(zhuǎn)換器裆赵,包括請求體,響應體的轉(zhuǎn)換
  final List<CallAdapter.Factory> callAdapterFactories;//請求適配器工廠列表
  final @Nullable Executor callbackExecutor;//回調(diào)執(zhí)行器
  final boolean validateEagerly;//立即驗證標志

可以看到Retrofit最重要的配置就是數(shù)據(jù)轉(zhuǎn)換器和請求適配器跺嗽,并且跟OkHttp強綁定战授。

retrofit最重要的方法就是create(),創(chuàng)建接口請求的實例桨嫁,這里使用動態(tài)代理

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {//如果為true陈醒,那么需要提前驗證請求方法的各個注解,參數(shù)等
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();//支持的平臺瞧甩,在Android 上時Android
          private final Object[] emptyArgs = new Object[0];

          @Override public @Nullable Object invoke(Object proxy, Method method,
              @Nullable Object[] args) throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            //調(diào)用的方法是Object的方法,那么就正常調(diào)用
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            //是否是Platform默認的方法
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            //如果都不是上面默認的方法弥鹦,那么就執(zhí)行到這里
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }
  1. 提前驗證的標志默認為false肚逸。如果為true的話,會提前確認好ServiceMethod彬坏,如果緩存中沒有的相應的ServiceMethod朦促,會創(chuàng)建ServiceMethod,并放入緩存
  2. 如果調(diào)用的方法是Object或者是platform的默認方法栓始,就是不是接口的請求的方法的話务冕,那么就走默認的方法
  3. 如果不滿足2,那么就確認是接口的請求方法幻赚,此時就會調(diào)用loadServiceMethod禀忆,得到相應的ServiceMethod后調(diào)用invoke(),接下來詳細分析
  ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;//如果緩存中有臊旭,那么就返回

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      //同步代碼塊,把相應ServiceMethod放入緩存
      if (result == null) {
          //這里就會調(diào)用ServiceMethod.parseAnnotations()
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
  1. 檢查緩存中是否有相應的ServiceMethod箩退,如果有的話那么取出來离熏,返回ServiceMethod
  2. 在同步代碼塊中會再次判斷緩存,如果還是沒有的話戴涝,就會創(chuàng)建ServiceMethod滋戳。這里SreviceMethod對應的是接口里的Method,對于同一個請求方法會復用同一個ServiceMethod啥刻。因為對于同一個方法來說奸鸯,請求適配器CallAdpater,數(shù)據(jù)轉(zhuǎn)換器ResponseConvert可帽,還有參數(shù)的注解娄涩,肯定都是一樣,只是可能每次請求參數(shù)的值不一樣蘑拯。 因為創(chuàng)建ServceMethod用到反射钝满,復用會提高性能。

然后接著調(diào)用loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
invoke()方法是ServiceMethod的抽象方法申窘,真正的實現(xiàn)是在HttpServiceMethod中弯蚜,那么繼續(xù)查看


  @Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);//構(gòu)造出輸入Retrofit的請求OkHttp,內(nèi)部包裝了Okhttp.Call
    return adapt(call, args);//adapt()在HttpServiceMethod中是抽象方法
  }
  1. 構(gòu)造出Retrofit.Call 的實現(xiàn)OkHttpCall,內(nèi)部封裝了OkHttp.Call
  2. 調(diào)用adapt() ,因為HttpServiceMethod的實現(xiàn)類有CallAdapted,SuspendForResponse奏黑,SuspendForBody亏掀,一般都是CallAdapted,所以看下CallAdapted中的實現(xiàn)
CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }

    @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);//調(diào)用了CallAdapter的adaptd()
    }
  1. 調(diào)用了callAdapter的adapt()呀邢,這里我們只追蹤RxJava2CallAdapter中的實現(xiàn)
  @Override public Object adapt(Call<R> call) {
     //對Retrofit.Call 再封裝,封裝成適配RxJava請求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;
    }

    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 RxJavaPlugins.onAssembly(observable);
  }

1.在RxJava2CallAdapterFactory 中,默認創(chuàng)建的是同步請求诵叁。即CallExecuteObservable

再看下同步請求CallExecuteObservable,異步請求類似钦椭,不再分析拧额。因為現(xiàn)在大家都對RxJava有一定的了解,所以直接看subscribeActual()

  @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    //這里執(zhí)行了一次clone()彪腔,因為Call是一次性的請求類型侥锦,所以會為每個Observer創(chuàng)建新的Call
    Call<T> call = originalCall.clone();
    CallDisposable disposable = new CallDisposable(call);
    observer.onSubscribe(disposable);
    if (disposable.isDisposed()) {
      return;
    }

    boolean terminated = false;
    try {
        //執(zhí)行OkHttpCall的同步請求
      Response<T> response = call.execute();
      if (!disposable.isDisposed()) {
      //傳遞給觀察者
        observer.onNext(response);
      }
      if (!disposable.isDisposed()) {
        terminated = true;
        observer.onComplete();
      }
    } catch (Throwable t) {
      Exceptions.throwIfFatal(t);
      if (terminated) {
        RxJavaPlugins.onError(t);
      } else if (!disposable.isDisposed()) {
        try {
          observer.onError(t);
        } catch (Throwable inner) {
          Exceptions.throwIfFatal(inner);
          RxJavaPlugins.onError(new CompositeException(t, inner));
        }
      }
    }
  }
  
  1. 對于OkHttpCall執(zhí)行一次clone(),因為OkHttpCall是一種一次性的類型德挣,只能執(zhí)行一次請求恭垦,所以需要clone(),為每個Observer創(chuàng)建新的請求
  2. 執(zhí)行OkHttpCall的同步請求,得到Retrofit.Response
  3. 傳遞給Observer

這時候就串起來了番挺,當調(diào)用請求方法獲得Observable時唠帝,調(diào)用subscribe(),觸發(fā)網(wǎng)絡請求建芙。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末没隘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子禁荸,更是在濱河造成了極大的恐慌右蒲,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赶熟,死亡現(xiàn)場離奇詭異瑰妄,居然都是意外死亡,警方通過查閱死者的電腦和手機映砖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門间坐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人邑退,你說我怎么就攤上這事竹宋。” “怎么了地技?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵蜈七,是天一觀的道長。 經(jīng)常有香客問我莫矗,道長飒硅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任作谚,我火速辦了婚禮三娩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘妹懒。我一直安慰自己雀监,他們只是感情好,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布眨唬。 她就那樣靜靜地躺著滔悉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪单绑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天曹宴,我揣著相機與錄音搂橙,去河邊找鬼。 笑死,一個胖子當著我的面吹牛区转,可吹牛的內(nèi)容都是我干的苔巨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼废离,長吁一口氣:“原來是場噩夢啊……” “哼侄泽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蜻韭,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤悼尾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后肖方,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闺魏,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年俯画,在試婚紗的時候發(fā)現(xiàn)自己被綠了析桥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡艰垂,死狀恐怖泡仗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情猜憎,我是刑警寧澤娩怎,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站拉宗,受9級特大地震影響峦树,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旦事,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一魁巩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧姐浮,春花似錦谷遂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蛋逾,卻和暖如春集晚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背区匣。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工偷拔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓莲绰,卻偏偏與公主長得像欺旧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蛤签,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容