網(wǎng)絡(luò)框架-Retrofit源碼解析

我們雖然窮劈彪,但是不能說謊,也不能打人顶猜,不是我們的東西粉臊,我們不能拿,要好好讀書驶兜,長(zhǎng)大要做個(gè)對(duì)社會(huì)有用的人扼仲。”——《長(zhǎng)江7號(hào)》

前言

本文從源碼角度分析Retrofit的工作流程抄淑,源碼基于2.7.2屠凶。并以一個(gè)例子來說明Retrofit的使用流程和源碼實(shí)現(xiàn)。

Retrofit的原理

Retrofit充當(dāng)了一個(gè)適配器(Adapter)的角色:將一個(gè)Java接口方法和注釋翻譯成一個(gè)Http請(qǐng)求肆资,然后用OkHttp去發(fā)送這個(gè)請(qǐng)求矗愧。實(shí)現(xiàn)這一功能需要通過動(dòng)態(tài)代理。

代理對(duì)象攔截真實(shí)對(duì)象的方法調(diào)用郑原,在真實(shí)對(duì)象調(diào)用前/后實(shí)現(xiàn)自己的邏輯調(diào)用

Retrofit的使用流程

第一步:Retrofit的創(chuàng)建過程

1.1 創(chuàng)建請(qǐng)求接口

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

1.2 構(gòu)建一個(gè) Retrofit實(shí)例
通過 create 方法生成 GitHubService的一個(gè)實(shí)現(xiàn)唉韭。

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    //.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    //.addConverterFactory(GsonConverterFactory.create()).
    .build();

至此,我們的Retrofit實(shí)例就創(chuàng)建成功了犯犁,通過代碼可知Retrofit的創(chuàng)建采用了構(gòu)建者模式属愤,我們來看Retrofit.Builder的源碼,其部分源碼如下:

public static final class Builder {
    //選擇平臺(tái):Android酸役,java等
    private final Platform platform;
    //okhttp的Call工廠類,Retrofit的網(wǎng)絡(luò)請(qǐng)求實(shí)現(xiàn)委托給okhttp住诸,此工廠類創(chuàng)建出的Call對(duì)象就為可以執(zhí)行網(wǎng)絡(luò)請(qǐng)求的okhttp3.Call對(duì)象。
    private @Nullable okhttp3.Call.Factory callFactory;
    //此為上面使用代碼中設(shè)置的baseUrl涣澡,Builder將我們?cè)O(shè)置的url封裝為HttpUrl對(duì)象
    private @Nullable HttpUrl baseUrl;
    //類型轉(zhuǎn)換工廠列表,用于將返回值轉(zhuǎn)換成想要的對(duì)象
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    //CallAdapter工廠列表
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    //回調(diào)線程池
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;
    ...
    public Builder() {
      this(Platform.get());
    }
}

上面列出了Retrofit.Builder中比較重要的成員變量及方法贱呐,其中部分含義已經(jīng)在注釋中寫明。其中CallAdapter字面含義“請(qǐng)求適配器”入桂,其具體作用是將網(wǎng)絡(luò)請(qǐng)求返回值封裝成我們想要的形式奄薇,比如經(jīng)常使用的RxJava2CallAdapterFactory便是將返回?cái)?shù)據(jù)形式封裝成Flowable對(duì)象來方便進(jìn)行流式編程,我們也可以自定義CallAdapter,不在本位重點(diǎn)討論范圍之內(nèi)抗愁。先來看Builder() 方法馁蒂,其只是簡(jiǎn)單調(diào)用了Platform.get()方法呵晚,Platform.get()方法源碼如下:

class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

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

Platform的get方法最終調(diào)用的是findPlatform方法,根據(jù)不同的運(yùn)行平臺(tái)來提供不同的線程池远搪。由此可見Builder()方法實(shí)際上就行選擇了一下平臺(tái)。
再來看Builder類中converterFactories和callAdapterFactories相關(guān)的設(shè)置方法addCallAdapterFactory()和addConverterFactory()其源碼如下:

    /** Add converter factory for serialization and deserialization of objects. */
    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    }

    /**
     * Add a call adapter factory for supporting service method return types other than {@link
     * Call}.
     */
    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    }

可見這兩個(gè)方法只是簡(jiǎn)單的將我們自定義的對(duì)象分別加入到對(duì)應(yīng)列表中逢捺。
繼續(xù)來看Build模式的最后一步.build()方法谁鳍,源碼如下:

public Retrofit build() {
      //1這一句告訴我們,baseUrl 是必不可少的劫瞳。
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //2這里如果你沒配置 callFactory , 會(huì)默認(rèn)配置為 OkHttpClient
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        //3
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        //4沒配置callbackExecutor的話倘潜,會(huì)默認(rèn)配置為 Platform 的 defaultCallbackExecutor
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      //5這里會(huì)把你所配置的 CallAdapter.Factory 加到 List 里去,最后把 Platform 默認(rèn)的 defaultCallAdapterFactory加到 List 的最后邊
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      //6這里一樣會(huì)把你配置的 Converter.Factory 加到 List 里去志于,但是會(huì)把一個(gè) BuiltInConverters 加到第一個(gè)涮因,再將platform.defaultConverterFactories()加到最后一個(gè),請(qǐng)注意這點(diǎn)伺绽。
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      // 先添加BuiltInConverters. 這樣不僅防止覆蓋其行為并且可以確保使用的所有類型的轉(zhuǎn)換器正確行為养泡。
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      //7
      converterFactories.addAll(platform.defaultConverterFactories());
      //8最后返回一個(gè) Retrofit 對(duì)象
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

部分代碼作用注釋已經(jīng)給出,通過源碼我們可以知道:

  • 注釋1處說明我們構(gòu)建Retrofit對(duì)象時(shí)baseUrl參數(shù)是必傳的奈应,不然會(huì)報(bào)出異常澜掩。
  • 注釋2和3處說明,如果需要對(duì) OkHttpClient 進(jìn)行設(shè)置杖挣,則可以構(gòu)建 OkHttpClient 對(duì)象肩榕,然后調(diào)用callFactory()方法將設(shè)置好的OkHttpClient傳進(jìn)去。如果沒有設(shè)置callFactory惩妇,則直接創(chuàng)建 OkHttpClient株汉。
  • 注釋4處的callbackExecutor即回調(diào)線程池,作用是將回調(diào)傳遞到 UI 線程歌殃,我們可以通過callbackExecutor()方法設(shè)置乔妈,一般我們使用默認(rèn)值即可。

下面我們對(duì)其中幾處進(jìn)行進(jìn)一步分析:
先來看看注釋4處的platform.defaultCallbackExecutor()是什么氓皱,通過前面的build()方法分析可知其主要會(huì)根據(jù)平臺(tái)返回一個(gè)platform對(duì)象褒翰,因此在android環(huán)境下會(huì)返回一個(gè)Android()對(duì)象。其源碼如下:

static final class Android extends Platform {
    Android() {
      super(Build.VERSION.SDK_INT >= 24);
    }

    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

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

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

可見android環(huán)境下構(gòu)建Retrofit對(duì)象時(shí)默認(rèn)的CallbackExecutor對(duì)象為MainThreadExecutor匀泊。
注釋5處platform.defaultCallAdapterFactories(callbackExecutor)又是什么呢优训,跟蹤其源碼如下:

List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
    return hasJava8Types
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
  }

可見其默認(rèn)為DefaultCallAdapterFactory對(duì)象轉(zhuǎn)化的列表。
注釋7處platform.defaultConverterFactories()的源碼為:

 List<? extends Converter.Factory> defaultConverterFactories() {
    return hasJava8Types
        ? singletonList(OptionalConverterFactory.INSTANCE)
        : emptyList();
  }

可見其為空列表各聘。

由注釋8可知build() 方法執(zhí)行完時(shí)我們會(huì)得到一個(gè)Retrofit對(duì)象揣非。其構(gòu)造時(shí)將converterFactories和callAdapterFactories封裝為了“只讀”列表。

第二步:創(chuàng)建網(wǎng)絡(luò)請(qǐng)求接口實(shí)例

得到Retrofit對(duì)象和前面定義好的請(qǐng)求接口后我們就可以創(chuàng)建網(wǎng)絡(luò)請(qǐng)求接口實(shí)例了躲因,具體代碼如下:

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

這里便體現(xiàn)了Retrofit的核心功能:將一個(gè)Java接口翻譯成一個(gè)Http請(qǐng)求早敬,前面原理部分說過實(shí)現(xiàn)這一功能需要通過動(dòng)態(tài)代理忌傻。下面我們具體分析源碼:

public <T> T create(final Class<T> service) {
    //檢驗(yàn)是否是接口及網(wǎng)絡(luò)接口方法預(yù)加載
    validateServiceInterface(service);
    //使用動(dòng)態(tài)代理獲取請(qǐng)求接口的所有接口注解配置,并且創(chuàng)建網(wǎng)絡(luò)請(qǐng)求接口實(shí)例
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          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 {
            // 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);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

可見搞监,其會(huì)先去執(zhí)行validateServiceInterface(service)方法水孩,跟蹤源碼如下:

private void validateServiceInterface(Class<?> service) {
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }

    Deque<Class<?>> check = new ArrayDeque<>(1);
    check.add(service);
    while (!check.isEmpty()) {
      Class<?> candidate = check.removeFirst();
      if (candidate.getTypeParameters().length != 0) {
        StringBuilder message = new StringBuilder("Type parameters are unsupported on ")
            .append(candidate.getName());
        if (candidate != service) {
          message.append(" which is an interface of ")
              .append(service.getName());
        }
        throw new IllegalArgumentException(message.toString());
      }
      Collections.addAll(check, candidate.getInterfaces());
    }
    //1
    if (validateEagerly) {
      Platform platform = Platform.get();
      for (Method method : service.getDeclaredMethods()) {
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
          loadServiceMethod(method);
        }
      }
    }
  }

根據(jù)源碼可知該方法前面主要做了一些校驗(yàn)工作,我們重點(diǎn)關(guān)注項(xiàng)目注釋1處的邏輯琐驴,這里用到了我們一直未說明的validateEagerly參數(shù)俘种,我們看看其作用是什么,根據(jù)源碼可知绝淡,其邏輯為遍歷前面定義好的網(wǎng)絡(luò)接口方法宙刘,然后回去執(zhí)行l(wèi)oadServiceMethod(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;
  }

這里我們看到一個(gè)serviceMethodCache對(duì)象牢酵,serviceMethodCache是Retrofit比Retrofit.Builder()多出來的成員變量悬包,跟蹤源碼:

public final class Retrofit {
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
...
}

ServiceMethod的源碼:

abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    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.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

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

可見ServiceMethod為一個(gè)抽象類,serviceMethodCache 為一個(gè)線程安全的馍乙、支持高效并發(fā)的HashMap布近,Key 是 Method,Value 是 ServiceMethod丝格。Method 就是上面接口中定義的方法吊输,而這個(gè)方法中有很多注解,@GET铁追、@Path 等等季蚂,ServiceMethod是將接口定義的方法和注解封裝后的對(duì)象。而變量名帶個(gè) Cache 說明琅束,會(huì)把這個(gè) Method 對(duì)應(yīng)的 ServiceMethod緩存起來扭屁。

由此可見validateServiceInterface(Class<?> service) 方法中注釋1部分整理邏輯為循環(huán)取出定義好接口中的 Method ,接著調(diào)用 loadServiceMethod 涩禀。 loadServiceMethod 里面會(huì)根據(jù) Method 生成一個(gè) ServiceMethod料滥,然后存入 serviceMethodCache ,所以那 validateEagerly 變量是用于正如其名字判斷是否需要提前驗(yàn)證解析的艾船。如果為true葵腹,會(huì)提前把接口中每個(gè)方法進(jìn)行解析得到一個(gè) ServiceMethod 對(duì)象,然后存入緩存中屿岂。

接著回到Retrofit.create()方法后面的代碼部分践宴,在執(zhí)行完 validateServiceInterface(service)方法之后會(huì)使用動(dòng)態(tài)代理獲取請(qǐng)求接口的所有接口注解配置,并且創(chuàng)建并返回T類型的網(wǎng)絡(luò)請(qǐng)求接口實(shí)例即GitHubService爷怀。

第三步:創(chuàng)建Call對(duì)象

得到網(wǎng)絡(luò)請(qǐng)求接口實(shí)例后阻肩,我們就可以通過動(dòng)態(tài)代理的方式去調(diào)用其中的方法,將其轉(zhuǎn)換成對(duì)應(yīng)的網(wǎng)絡(luò)請(qǐng)求的Call對(duì)象實(shí)例了运授。具體示例代碼如下:

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

service為前面Retrofit類create()方法創(chuàng)建的接口api的動(dòng)態(tài)代理對(duì)象烤惊,所以調(diào)用其中方法比如service.listRepos("octocat")時(shí)會(huì)觸發(fā)代理對(duì)象上的invoke方法乔煞,再來看Retrofit類create()方法中復(fù)寫的invoke()的源碼:

public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          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方法直接執(zhí)行
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            //此處為java8方法,android環(huán)境下忽略
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            //動(dòng)態(tài)解析網(wǎng)絡(luò)接口方法并返回
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

通過源碼可知其最終會(huì)調(diào)用loadServiceMethod(method).invoke(args != null ? args : emptyArgs)方法并返回柒室,其中l(wèi)oadServiceMethod(method)前面我們已經(jīng)提到過渡贾,其主要作用就是解析定義好的網(wǎng)絡(luò)接口,將其中的方法和注釋解析并封裝成一個(gè)ServiceMethod對(duì)象并緩存到Map中⌒塾遥現(xiàn)在我們?cè)偕钊肴ジM(jìn)其中的源碼邏輯看看它都具體做了哪些工作空骚,loadServiceMethod(Method 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;
  }

當(dāng)我們不能從緩存的Map中找到對(duì)應(yīng)方法的緩存時(shí)會(huì)調(diào)用ServiceMethod.parseAnnotations(this, method)方法,其源碼如下:

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    //1
    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.");
    }
    //2
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

注釋1中可見方法會(huì)先創(chuàng)建一個(gè)RequestFactory對(duì)象不脯,通過它的名字我們猜想到它應(yīng)該是用來構(gòu)建網(wǎng)絡(luò)請(qǐng)求Request對(duì)象的府怯,我們來看看這個(gè)RequestFactory的源碼:

final class RequestFactory {
  //調(diào)用parseAnnotations方法最終會(huì)通過構(gòu)建者模式創(chuàng)建一個(gè)RequestFactory對(duì)象
  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }

  private final Method method;
  private final HttpUrl baseUrl;
  final String httpMethod;
  private final @Nullable String relativeUrl;
  private final @Nullable Headers headers;
  private final @Nullable MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;
  final boolean isKotlinSuspendFunction;
...
//該方法用于創(chuàng)建一個(gè)okhttp3的網(wǎng)絡(luò)請(qǐng)求對(duì)象Request用于具體實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求
  okhttp3.create(Object[] args) throws IOException {
 ...
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
        headers, contentType, hasBody, isFormEncoded, isMultipart);

    List<Object> argumentList = new ArrayList<>(argumentCount);
    for (int p = 0; p < argumentCount; p++) {
      argumentList.add(args[p]);
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.get()
        .tag(Invocation.class, new Invocation(method, argumentList))
        .build();
  }

  /**
   * 檢查接口方法上的注釋以構(gòu)造可重用的服務(wù)方法刻诊。 這個(gè)
   *可能需要繁重的反射機(jī)制防楷,因此每個(gè)服務(wù)方法最好只構(gòu)建一次
   *并重用。 生成器不能重復(fù)使用则涯。
   */
  static final class Builder {
    // Upper and lower characters, digits, underscores, and hyphens, starting with a character.
    private static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
    private static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
    private static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);

    final Retrofit retrofit;
    final Method method;
    //方法注解數(shù)組
    final Annotation[] methodAnnotations;
    //參數(shù)注解二位數(shù)組
    final Annotation[][] parameterAnnotationsArray;
    //參數(shù)類型數(shù)組
    final Type[] parameterTypes;

    @Nullable String httpMethod;
    boolean hasBody;
    boolean isFormEncoded;
    boolean isMultipart;
    @Nullable String relativeUrl;
    @Nullable Headers headers;
    @Nullable MediaType contentType;
    ... 

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

    RequestFactory build() {
      for (Annotation annotation : methodAnnotations) {
       //解析方法的注解
        parseMethodAnnotation(annotation);
      }
      ...//忽略一堆網(wǎng)絡(luò)協(xié)議規(guī)則校驗(yàn)
      
      return new RequestFactory(this);
    }

     //方法主要作用就是解析注解設(shè)置成員變量的值
    private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } 
      ...
        isFormEncoded = true;
      }
    }
    //方法主要作用就是解析注解設(shè)置成員變量的值
    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      if (this.httpMethod != null) {
        throw methodError(method, "Only one HTTP method is allowed. Found: %s and %s.",
            this.httpMethod, httpMethod);
      }
      ...
      this.relativeUrlParamNames = parsePathParameters(value);
    }
      //方法主要作用是解析并創(chuàng)建Headers實(shí)例
    private Headers parseHeaders(String[] headers) {
      Headers.Builder builder = new Headers.Builder();
      ...
      return builder.build();
    }
    ...
}

代碼值列出了部分成員變量复局,了解retrofit使用方法就能見文知意了解參數(shù)含義;列出其中主要的方法并簡(jiǎn)單加以注釋粟判。通過源碼我們了解到這個(gè)類的主要作用就是去解析第一步創(chuàng)建好的網(wǎng)絡(luò)請(qǐng)求接口中的方法和注解最終將其轉(zhuǎn)換成okhttp3的網(wǎng)絡(luò)請(qǐng)求Request對(duì)象亿昏。
再回到ServiceMethod類的parseAnnotations(Retrofit retrofit, Method method) 中去,再其中注釋1解析網(wǎng)絡(luò)接口并創(chuàng)建好request對(duì)象后又在注釋2處調(diào)用了HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)方法档礁,并將其傳了進(jìn)去角钩。繼續(xù)跟進(jìn)源碼:

/** Adapts an invocation of an interface method into an HTTP call. */
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
  /**
   * Inspects the annotations on an interface method to construct a reusable service method that
   * speaks HTTP. This requires potentially-expensive reflection so it is best to build each service
   * method only once and reuse it.
   */
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
     ...
    //1
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    ...
    //2
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
    //此處默認(rèn)為callFactory = new OkHttpClient();
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      //3
      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);
    }
  }
}

忽略koltlin協(xié)程相關(guān)功能,重點(diǎn)關(guān)注代碼流程呻澜,在注釋1調(diào)用createCallAdapter(retrofit, method, adapterType, annotations)方法递礼,跟蹤發(fā)現(xiàn)它又會(huì)調(diào)用retrofit.nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,Annotation[] annotations)方法:

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    ...
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      //1
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
  ...
  }

該方法會(huì)循環(huán)遍歷我們之前設(shè)置好的callAdapterFactories并注釋1處調(diào)用其get()方法,由于我們?yōu)轱@示指定CallAdapterFactory前面已經(jīng)分Retrofit默認(rèn)會(huì)設(shè)置為DefaultCallAdapterFactory羹幸,那就來看看其get()方法源碼:

@Override public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    ...

    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return executor == null
            ? call
            : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

可見其會(huì)返回一個(gè)CallAdapter對(duì)象脊髓。其源碼先不作分析,接著回到HttpServiceMethod的parseAnnotations源碼注釋2處栅受,此處調(diào)用createResponseConverter ()創(chuàng)建一個(gè)Converter對(duì)象将硝,其內(nèi)部流程與callAdapter的創(chuàng)建類似這里就不再做分析了,只是作用為將返回值類型通過此處創(chuàng)建的Conver對(duì)象轉(zhuǎn)化為我們想要的數(shù)據(jù)類型屏镊。比如我們?cè)賱?chuàng)建Retrofit實(shí)例時(shí)經(jīng)常設(shè)置的GsonConverterFactory就是講返回值通過gson解析成想要的實(shí)體類依疼。
接著分析HttpServiceMethod的parseAnnotations源碼的注釋3處,此處調(diào)用new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter)方法而芥,并將之前設(shè)置的參數(shù)全傳遞了進(jìn)去涛贯,來看源碼:

CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }

HttpServiceMethod(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
      Converter<ResponseBody, ResponseT> responseConverter) {
    this.requestFactory = requestFactory;
    this.callFactory = callFactory;
    this.responseConverter = responseConverter;
  }

可見該方法主要邏輯為給自己的成員變量賦值。所以loadServiceMethod()中解析網(wǎng)絡(luò)接口定義并封裝成ServiceMethod對(duì)象時(shí)還做了一下幾件事情:

  • 解析網(wǎng)絡(luò)接口定義蔚出,根據(jù)方法和注解創(chuàng)建網(wǎng)絡(luò)請(qǐng)求的request實(shí)例弟翘;
  • 根據(jù)我們?cè)O(shè)置的CallFactory設(shè)置okhttp3的call對(duì)象虫腋,默認(rèn)為new OkHttpClient();
  • 根據(jù)我們?cè)O(shè)置的CallAdapterFactory創(chuàng)建好calladapter對(duì)象;
  • 根據(jù)我們?cè)O(shè)置的ConverterFactory創(chuàng)建網(wǎng)絡(luò)返回值轉(zhuǎn)換converter對(duì)象稀余;
  • 將所有上面這些對(duì)象設(shè)置給HttpServiceMethod的成員變量加以管理悦冀,等待后續(xù)使用。

繼續(xù)回到Retrofit的create()通過動(dòng)態(tài)代理重寫的invoke()源碼中睛琳,其最終調(diào)用loadServiceMethod(method).invoke(args != null ? args : emptyArgs)方法通過前面的分析可知其執(zhí)行的是HttpServiceMethod的invoke()方法盒蟆,源碼如下:

@Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

方法創(chuàng)建了一個(gè)OkHttpCall對(duì)象,通過其名稱可知其為okhttp實(shí)現(xiàn)的網(wǎng)絡(luò)請(qǐng)求的具體call對(duì)象的封裝师骗。通過起源也可發(fā)現(xiàn)其集成Call類并在內(nèi)部維護(hù)了整套由okhttp3實(shí)現(xiàn)的網(wǎng)絡(luò)請(qǐng)求功能具體實(shí)現(xiàn)及返回?cái)?shù)據(jù)解析parseResponse()方法的實(shí)現(xiàn)其內(nèi)部通過前面創(chuàng)建的convert對(duì)象來解析返回結(jié)果历等。其源碼如下:

final class OkHttpCall<T> implements Call<T> {
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) {
      rawBody.close();
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
      //通過前面創(chuàng)建好并傳遞過來的converter對(duì)象解析返回值
      T body = responseConverter.convert(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;
    }
  }
}

其中正常網(wǎng)絡(luò)請(qǐng)求的方法為okhttp網(wǎng)絡(luò)請(qǐng)求實(shí)現(xiàn),源碼就不貼了辟癌,不了解okhttp網(wǎng)絡(luò)請(qǐng)求原理的可以去查看我之前發(fā)布的okhttp框架源碼解析寒屯。接著其由調(diào)用了adapt(call, args)方法,通過前面分析知其實(shí)際調(diào)用了其子類CallAdapted的adapt方法黍少,源碼如下:

@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }

通過loadServiceMethod()內(nèi)部邏輯的分析第三步可知其實(shí)際調(diào)用的是創(chuàng)建好的calladapter對(duì)象的adapte方法寡夹,這里再重貼一遍上面為分析完的DefaultCallAdapterFactory get()方法創(chuàng)建的calladapter方法的源碼:

@Override public @Nullable CallAdapter<?, ?> get(
    ...
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return executor == null
            ? call
            : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

由代碼可知,其最終又調(diào)用了new ExecutorCallbackCall<>(executor, call)方法厂置,其源碼為:

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

功能為給ExecutorCallbackCall類內(nèi)部成員變量賦值以待后續(xù)執(zhí)行網(wǎng)絡(luò)請(qǐng)求時(shí)使用菩掏。由此我們前面的這行代碼終于分析完了:

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

其通過動(dòng)態(tài)代理最終得到了一個(gè)ExecutorCallbackCall對(duì)象實(shí)例。并且通過其成員變量名稱猜想之后的網(wǎng)絡(luò)同步異步請(qǐng)求應(yīng)該是被其delegate成員代理實(shí)現(xiàn)的昵济。請(qǐng)求返回的結(jié)果的線程切換時(shí)由callbackExecutor 處理的智绸。

第四步:通過創(chuàng)建好的由Retrofit封裝的Call對(duì)象來進(jìn)行網(wǎng)絡(luò)通信

Retrofit將Call對(duì)象進(jìn)行了進(jìn)一步封裝,其內(nèi)部交由OkHttpCall這個(gè)實(shí)習(xí)類來通過okhttp具體實(shí)現(xiàn)網(wǎng)絡(luò)通信访忿。
現(xiàn)在以異步請(qǐng)求為例看一看Retrofit網(wǎng)絡(luò)請(qǐng)求的實(shí)現(xiàn)瞧栗,通過起那么分析指導(dǎo)enqueue()的代碼實(shí)現(xiàn)默認(rèn)其實(shí)為ExecutorCallbackCall類的enqueue()方法如下:

@Override public void enqueue(final Callback<T> callback) {
      Objects.requireNonNull(callback, "callback == null");
      // 真正的Call請(qǐng)求確實(shí)由delegate(前面分析的OkHttpCall對(duì)象)去執(zhí)行的
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          // 回調(diào)后 利用 MainThreadExecutor中的 Handler 切換到主線程中去。
          callbackExecutor.execute(() -> {
            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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
        }
      });
    }

可以看到是 delegate 執(zhí)行了 enqueue 操作醉顽,而 delegate 就是我們的 OkHttpCall 沼溜,在 OkHttpCall 里的 enqueue 方法是這樣工作的。通過 okhttp3.Call call = serviceMethod.toCall(args); 構(gòu)建一個(gè)真正執(zhí)行請(qǐng)求的 Call 游添,即把請(qǐng)求交給 okhttp 去完成系草。而構(gòu)建一個(gè) Call 利用到了 ServiceMethod 中的 ParameterHandler 對(duì)象,這個(gè)對(duì)象是用來處理參數(shù)的唆涝。 它會(huì)把具體參數(shù)的值與 RequestBuilder 綁定起來找都。當(dāng)然也用到了 ServiceMethod 自己,ServiceMethod 類似請(qǐng)求響應(yīng)的大管家廊酣。
別忘了拿到響應(yīng)后能耻,在 okhttp3.Callback 中會(huì)去調(diào)用 response = parseResponse(rawResponse); 將響應(yīng)轉(zhuǎn)換成自己想要的格式,即定義的 Converter 。關(guān)于返回值得解析在此就不繼續(xù)解讀了晓猛,因?yàn)椴皇俏覀兇宋牡闹攸c(diǎn)饿幅。

總結(jié)

到此,整個(gè)Retrofit的流程終于走完了戒职。簡(jiǎn)單總結(jié)如下:

  1. 通過建造者模式構(gòu)建一個(gè)Retrofit實(shí)例栗恩,配置baseUrl,callAdapterFactory(將代理返回的Call對(duì)象轉(zhuǎn)化為其他洪燥,比如Rxjava的Observer)磕秤,converterFactory(結(jié)果的轉(zhuǎn)化器,將請(qǐng)求的結(jié)果轉(zhuǎn)化為特定的對(duì)象時(shí)使用捧韵,比如GsonConverterFactory)市咆。
  2. 通過Retrofit對(duì)象的create(Class<T> service)方法返回一個(gè)Service的動(dòng)態(tài)代理對(duì)象,在調(diào)用service的方法的時(shí)候再来,就是調(diào)用動(dòng)態(tài)代理的invoke方法蒙兰。
  3. 調(diào)用代理的invoke方法的時(shí)候,會(huì)將網(wǎng)絡(luò)接口api進(jìn)行解析其弊,解析我們定義的接口方法以及配置的各種注解癞己,最后構(gòu)造成ServiceMethod對(duì)象膀斋,并將結(jié)果緩存起來梭伐。解析過程中會(huì)根據(jù)我們的配置創(chuàng)建接口描述的Request對(duì)象、CallFactory設(shè)置okhttp3的call對(duì)象仰担、calladapter對(duì)象糊识、converter對(duì)象。接著又創(chuàng)建OkHttpCall實(shí)例來管理真正的網(wǎng)絡(luò)實(shí)現(xiàn),然后通過callAdapter轉(zhuǎn)化為用戶希望得到的返回對(duì)象摔蓝,默認(rèn)是直接返回ExecutorCallbackCall對(duì)象赂苗。
  4. 返回Call對(duì)象之后,我們?cè)僬{(diào)用同步execute或者異步enqueue請(qǐng)求贮尉,方法內(nèi)部會(huì)通過Okhttp實(shí)現(xiàn)的網(wǎng)絡(luò)請(qǐng)求方法拌滋。并根據(jù)上一步創(chuàng)建的converter對(duì)象將返回?cái)?shù)據(jù)解析成我們想要的實(shí)體類豪娜。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末快鱼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子世落,更是在濱河造成了極大的恐慌魏铅,老刑警劉巖昌犹,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異览芳,居然都是意外死亡斜姥,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铸敏,“玉大人缚忧,你說我怎么就攤上這事¤颈剩” “怎么了搔谴?”我有些...
    開封第一講書人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)桩撮。 經(jīng)常有香客問我敦第,道長(zhǎng),這世上最難降的妖魔是什么店量? 我笑而不...
    開封第一講書人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任芜果,我火速辦了婚禮,結(jié)果婚禮上融师,老公的妹妹穿的比我還像新娘右钾。我一直安慰自己,他們只是感情好旱爆,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開白布舀射。 她就那樣靜靜地躺著,像睡著了一般怀伦。 火紅的嫁衣襯著肌膚如雪脆烟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,807評(píng)論 1 314
  • 那天房待,我揣著相機(jī)與錄音邢羔,去河邊找鬼。 笑死桑孩,一個(gè)胖子當(dāng)著我的面吹牛拜鹤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播流椒,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼敏簿,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了宣虾?” 一聲冷哼從身側(cè)響起惯裕,我...
    開封第一講書人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎安岂,沒想到半個(gè)月后轻猖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡域那,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年咙边,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了猜煮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡败许,死狀恐怖王带,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情市殷,我是刑警寧澤愕撰,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站醋寝,受9級(jí)特大地震影響搞挣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜音羞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一囱桨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嗅绰,春花似錦舍肠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至财边,卻和暖如春肌括,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背制圈。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來泰國打工们童, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留畔况,地道東北人鲸鹦。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像跷跪,于是被迫代替她去往敵國和親馋嗜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

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