Retrofit源碼解析

本文是基于Retrofit2.6.0源碼的應(yīng)用于分析。

Retrofit的應(yīng)用

  • 定義一個(gè)網(wǎng)絡(luò)請求接口
public interface GitHub {
  @GET("/repos/{owner}/{repo}/contributors")
  Call<List<Contributor>> contributors(@Path("owner") String owner, 
        @Path("repo") String repo);
}
  • 初始化一個(gè)Retrofit實(shí)例,采用構(gòu)造者模式鏈?zhǔn)秸{(diào)用
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(API_URL)
    .addConverterFactory(GsonConverterFactory.create())
    .build();
  • 創(chuàng)建一個(gè)接口實(shí)現(xiàn)類Api:
//同步請求
GitHub github = retrofit.create(GitHub.class);
Call<List<Contributor>> call = github.contributors("square", "retrofit");
List<Contributor> contributors = call.execute().body();
//異步請求
call.enqueue(new Callback<List<Contributor>>() {
      @Override
      public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
      }
      @Override
      public void onFailure(Call<List<Contributor>> call, Throwable t) {
      }
    });

就這樣我們完成了一次網(wǎng)絡(luò)請求。
下面我們來看下源碼中的具體實(shí)現(xiàn)。


Retrofit的源碼實(shí)現(xiàn)
Retrofit retrofit = new Retrofit.Builder()
     .baseUrl(API_URL)
     .addConverterFactory(GsonConverterFactory.create())
     .build();
一. 先從Retrofit.Builder開始Builder調(diào)用了
public Builder() {
   this(Platform.get());
}

主要對Platform進(jìn)行了實(shí)例化在Platform的實(shí)例化中主要調(diào)用了

private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

主要通過反射判斷了Retrofit是在Java平臺還是Android平臺使用,本文是假設(shè)是在Android中使用,返回了一個(gè)Android繼承Platform的實(shí)例并重構(gòu)了部分方法。
.baseUrl(API_URL)沒什么可說的主要是為Builder中的baseUrl賦值為一個(gè)HttpUrl;

.addConverterFactory(GsonConverterFactory.create())
  • 添加一個(gè)gson轉(zhuǎn)換器工廠,GsonConverterFactory繼承Converter.Factory,從字面翻譯就可以理解轉(zhuǎn)換工廠,提供了3個(gè)空實(shí)現(xiàn)返回的方法。再看GsonConverterFactory的實(shí)現(xiàn)
。。。省略主要看這兩個(gè)方法
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type,
 Annotation[] annotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations
, Annotation[] methodAnnotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }

這兩個(gè)方法主要分別實(shí)現(xiàn)了ResponseBody轉(zhuǎn)化為實(shí)體類和實(shí)體類轉(zhuǎn)化為RequestBody。

  • 再看下最后的build()方法
public Retrofit build() {
      //判斷url
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //未傳入callFactory的話默認(rèn)為OkHttpClient請求可以看出Retrofit框架可以
      //使用其他網(wǎng)絡(luò)請求,它只是對網(wǎng)絡(luò)請求進(jìn)行了封裝方便使用
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      //未傳入線程池的話使用平臺默認(rèn)線程池Android平臺默認(rèn)為主線程
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // 添加默認(rèn)的CallAdapter
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      // 轉(zhuǎn)化工廠
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

     //將添加的配置都加入轉(zhuǎn)化
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());
      //最后對Retrofit 進(jìn)行實(shí)例化 并賦值初始化參數(shù)。
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
二、下面看下Retrofit中重要的一步,根據(jù)傳入的接口返回一個(gè)代理實(shí)例:
GitHub github = retrofit.create(GitHub.class);

該方法調(diào)用了Retrofit中的create方法

  public <T> T create(final Class<T> service) {
    //先判斷是否是接口
    Utils.validateServiceInterface(service);
    //默認(rèn)為false
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //返回一個(gè)動態(tài)代理
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          //當(dāng)前為Android平臺
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];

          @Override public @Nullable Object invoke(Object proxy, Method method,
              @Nullable Object[] args) throws Throwable {
            // 判斷是否為Object
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            //sdk 24一下會直接返回flase 
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            //最終調(diào)用
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

至此Retrofit.create()只是生成了一個(gè)動態(tài)代理對象真正調(diào)用會是根據(jù)代理對象去調(diào)用其中方法:

Call<List<Contributor>> call = github.contributors("square", "retrofit");

根據(jù)代碼分析會調(diào)用并返回loadServiceMethod(method).invoke(args != null ? args : emptyArgs);的值,主要從緩存中取出ServiceMethod,緩存中沒有的話會調(diào)用ServiceMethod.parseAnnotations(this, method)生成:

  ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

ServiceMethod.parseAnnotations(this, method)中主要調(diào)用了 ServiceMethod.parseAnnotations(this, method)在方法又調(diào)用了Retrofit中的nextCallAdapter 與 nextResponseBodyConverter 得到了responseConverter與callFactory,并實(shí)例化一個(gè)SuspendForBody返回

 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();
    }

    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.");
    }

    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    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);
    }
  }
  • 我們再回到Retrofit中的Retrofit.create()方法,loadServiceMethod(method)從上面分析我們知道得到的是SuspendForBody,SuspendForBody繼承了HttpServiceMethod,實(shí)際上是調(diào)用HttpServiceMethod的invoke()方法;invoke方法中實(shí)例了一個(gè)OkHttpCall對象并傳入調(diào)用了SuspendForBody的adapt方法
  @Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }
  • SuspendForBody的adapt()方法,
    @Override protected Object adapt(Call<ResponseT> call, Object[] args) {
      call = callAdapter.adapt(call);

      //noinspection unchecked Checked by reflection inside RequestFactory.
      Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
      return isNullable
          ? KotlinExtensions.awaitNullable(call, continuation)
          : KotlinExtensions.await(call, continuation);
    }

在未設(shè)置CallAdapter的情況下CallAdapter.adapt()最終調(diào)用的默認(rèn)DefaultCallAdapterFactory.get()生成的CallAdapter,為ExecutorCallbackCall。至此我們得到了Call<List<Contributor>>。

三、接下來繼續(xù)看應(yīng)用層代碼:
List<Contributor> contributors = call.execute().body();

從上面可知call是ExecutorCallbackCall類型的,call.execute()應(yīng)該調(diào)用的是ExecutorCallbackCall中的方法,實(shí)際就是調(diào)用ExecutorCallbackCall實(shí)例化時(shí)傳入的call,從上文的代碼可知call為HttpServiceMethod.invoke()方法中生成的OkHttpCall,實(shí)際調(diào)用了它的execute()方法

    @Override public Response<T> execute() throws IOException {
      return delegate.execute();
    }
  • OkHttpCall的的execute()方法主要調(diào)用了createRawCall()根據(jù)之前構(gòu)建的請求工廠,創(chuàng)建了okhttp3.Call這也是我們調(diào)用OkhttpClient進(jìn)行請求的真實(shí)請求,之后調(diào)用了call.execute()發(fā)起請求并處理返回?cái)?shù)據(jù)。
@Override public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
      .....

      if (creationFailure != null) {
      ......
      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();
    }
    //發(fā)起請求并處理返回體
    return parseResponse(call.execute());
  }

這樣我們Retrofit發(fā)起的一次同步請求就分析完成了,大體上了解了請求流程。

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

相關(guān)閱讀更多精彩內(nèi)容

  • 適配器模式上一篇文章我們已經(jīng)分析了Retrofit解析注解封裝進(jìn)ServiceMethod的流程,讀者在這里要記住...
    andcoder閱讀 775評論 0 2
  • 如果你還沒了解Retrofit如何使用,可以先查看這篇文章:Retrofit使用指南 一般分析源碼都習(xí)慣從使用開始...
    一只小雞仔閱讀 796評論 1 4
  • Retrofit在代碼中的構(gòu)建方式 根據(jù)構(gòu)建方式,我們先來看一下Retrofit類源碼 (1)Retrofit中的...
    dlihasa閱讀 390評論 0 4
  • 一、什么是Retrofit A type-safe HTTP client for Android and Jav...
    andcoder閱讀 846評論 2 3
  • Retrofit簡介 Retrofit是一個(gè)基于OKHttp的RESTful網(wǎng)絡(luò)請求框架。簡單來說,Retrofi...
    htkeepmoving閱讀 460評論 0 0

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