Retrofit源碼分析

Retrofit其實(shí)是對(duì)OkHttp的一個(gè)封裝,方便進(jìn)行網(wǎng)絡(luò)API的調(diào)用

Paste_Image.png

使用方法:定義一個(gè)接口,用注解標(biāo)注方法,每個(gè)方法對(duì)應(yīng)一個(gè)API接口。

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/").build();

GitHubService service = retrofit.create(GitHubService.class);

Call<List<Repo>> repos = service.listRepos("octocat");

Retrofit.Builder.build:

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

callFactory是OkHttpClient,callBackExecutor在android平臺(tái)上是MainThreadExecutor,CallAdaptorFactory在android平臺(tái)上是ExecutorCallAdapterFactory,如果有自定義converterFactory也會(huì)傳給Retrofit實(shí)例。validateEagerly代表create service時(shí)就驗(yàn)證全部的方法,否則只有調(diào)用時(shí)才驗(yàn)證。

先看看如何create service,Retrofit.create:

  @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  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, 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 serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

對(duì)接口創(chuàng)建動(dòng)態(tài)代理。調(diào)用loadServiceMethod創(chuàng)建ServiceMethod,然后創(chuàng)建OkHttpCall(實(shí)際上包裝okhttp3.Call),然后再用service.callAdaptor適配一下(android平臺(tái)上默認(rèn)是ExecutorCallbackCall,目的是在調(diào)用enqueue進(jìn)行異步調(diào)用時(shí)在主線程上進(jìn)行回調(diào)),converterFactory默認(rèn)為BuiltInConverters;。包裝關(guān)系:

Paste_Image.png

來看看ServiceMethod的創(chuàng)建流程,Retrofit.loadServiceMethod:

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

先查看cache里有沒有,否則用ServiceMethod.builder創(chuàng)建一個(gè),放入cache中

    public Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

Builder構(gòu)造函數(shù)中得到method的注解,parameter的type,parameter的注解

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      responseConverter = createResponseConverter();

      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      if (httpMethod == null) {
        throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      if (!hasBody) {
        if (isMultipart) {
          throw methodError(
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
          throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }

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

      if (relativeUrl == null && !gotUrl) {
        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError("Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError("Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError("Multipart method must contain at least one @Part.");
      }

      return new ServiceMethod<>(this);
    }

    private CallAdapter<?> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      if (Utils.hasUnresolvableType(returnType)) {
        throw methodError(
            "Method return type must not include a type variable or wildcard: %s", returnType);
      }
      if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
      }
      Annotation[] annotations = method.getAnnotations();
      try {
        return retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }

build里先會(huì)創(chuàng)建CallAdapter。

    private CallAdapter<?> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      if (Utils.hasUnresolvableType(returnType)) {
        throw methodError(
            "Method return type must not include a type variable or wildcard: %s", returnType);
      }
      if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
      }
      Annotation[] annotations = method.getAnnotations();
      try {
        return retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }

從CallAdapterFactories里找到第一個(gè)創(chuàng)建CallAdapter的Factory。這里是ExecutorCallAdapterFactory

  @Override
  public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public <R> Call<R> adapt(Call<R> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

檢查返回的類型是不是Call,然后得到Call的泛型類型。返回CallAdaptor。接著回到build

responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      responseConverter = createResponseConverter();

      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

得到responseType,這里是List<Repo>,創(chuàng)建responseConverter。調(diào)用parseMethodAnnotation解析method的注解。這里代碼較多,我們就看get的處理邏輯

    private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } 

    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      if (this.httpMethod != null) {
        throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
            this.httpMethod, httpMethod);
      }
      this.httpMethod = httpMethod;
      this.hasBody = hasBody;

      if (value.isEmpty()) {
        return;
      }

      // Get the relative URL path and existing query string, if present.
      int question = value.indexOf('?');
      if (question != -1 && question < value.length() - 1) {
        // Ensure the query string does not have any named parameters.
        String queryParams = value.substring(question + 1);
        Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
        if (queryParamMatcher.find()) {
          throw methodError("URL query string \"%s\" must not have replace block. "
              + "For dynamic query parameters use @Query.", queryParams);
        }
      }

      this.relativeUrl = value;
      this.relativeUrlParamNames = parsePathParameters(value);
    }

根據(jù)注解確定httpmethod,得到注解里的值,判斷有沒有body。
從注解的path中得到需要替換的path,放入relativeUrlParamNames中,在這里就是user

回到build

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

對(duì)每一個(gè)參數(shù),根據(jù)其上的注解,創(chuàng)建paramterHandler

最后返回一個(gè)創(chuàng)建的ServiceMethod。然后用這個(gè)ServiceMethod創(chuàng)建OkHttpCall,然后再創(chuàng)建ExecutroCallbackCall。

      return new ServiceMethod<>(this);

調(diào)用service的方法會(huì)返回一個(gè)ExecutroCallbackCall。要獲得response,需要調(diào)用call上的execute。ExecutroCallbackCall的execute方法是調(diào)用OkHttpCall的execute方法。

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

    synchronized (this) {
      .....
      call = rawCall;
      if (call == null) {
        try {
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException e) {
          creationFailure = e;
          throw e;
        }
      }
    }
    return parseResponse(call.execute());
  }

先調(diào)用createRawCall創(chuàng)建一個(gè)rawCall,也就是Okhttp3的call,然后調(diào)用它的execute方法,將返回的response傳給parseResponse。

  private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

先調(diào)用serviceMethod.toRequest創(chuàng)建Okhttp的request,args是service方法調(diào)用的參數(shù),然后調(diào)用OkHttpClient創(chuàng)建Call。

  Request toRequest(Object... args) throws IOException {
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
        contentType, hasBody, isFormEncoded, isMultipart);

    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args != null ? args.length : 0;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
    }

    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.build();
  }

調(diào)用ParamterHandler來處理每個(gè)參數(shù),然后生成Okttp中的request。

最后調(diào)用call.execute方法得到okhttp的response,然后調(diào)用parseResponse來解析這個(gè)response。

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();

    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
      try {
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }

    if (code == 204 || code == 205) {
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }

最后是調(diào)用responseConverter.convert來講okhttp的ResponseBody轉(zhuǎn)換成List<Repo>, 然后放入Retrofit的response的body中

T body = serviceMethod.toResponse(catchingBody); -> responseConverter.convert(body);
return Response.success(body, rawResponse);

最后將這個(gè)Retrofit的response從execute中返回出去

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

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

  • 最近非常流行 Retrofit+RxJava+OkHttp 這一整套的網(wǎng)絡(luò)請(qǐng)求和異步操作的開源框架,從 Jake ...
    慌不要慌閱讀 2,031評(píng)論 1 7
  • Retrofit Version:2.2.0分析代碼地址:https://github.com/Blankeer/...
    Blankeer閱讀 259評(píng)論 0 1
  • 本篇為個(gè)人理解心得 多有不詳細(xì) 還請(qǐng)移步:http://m.itdecent.cn/p/0c055ad46b...
    番茄tomato閱讀 244評(píng)論 0 1
  • Retrofit是用在網(wǎng)絡(luò)請(qǐng)求中非常常用的一個(gè)庫(kù),這里從2.5.0版本的源碼去分析一下它的工作機(jī)制??纯此鼘?shí)際做了...
    kisass閱讀 273評(píng)論 0 0
  • 黑龍閣主 最近有一句話比較流行:回歸傳統(tǒng)。而回歸傳統(tǒng)實(shí)質(zhì)上就是認(rèn)識(shí)歷史,了解歷史,以史為鑒。中華歷史上下五千年,傳...
    Luibe閣主閱讀 334評(píng)論 0 3

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