网络框架-Retrofit源码解析

我们虽然穷,但是不能说谎,也不能打人,不是我们的东西,我们不能拿,要好好读书,长大要做个对社会有用的人。”——《长江7号》

前言

本文从源码角度分析Retrofit的工作流程,源码基于2.7.2。并以一个例子来说明Retrofit的使用流程和源码实现。

Retrofit的原理

Retrofit充当了一个适配器(Adapter)的角色:将一个Java接口方法和注释翻译成一个Http请求,然后用OkHttp去发送这个请求。实现这一功能需要通过动态代理。

代理对象拦截真实对象的方法调用,在真实对象调用前/后实现自己的逻辑调用

Retrofit的使用流程

第一步:Retrofit的创建过程

1.1 创建请求接口

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

1.2 构建一个 Retrofit实例
通过 create 方法生成 GitHubService的一个实现。

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

至此,我们的Retrofit实例就创建成功了,通过代码可知Retrofit的创建采用了构建者模式,我们来看Retrofit.Builder的源码,其部分源码如下:

public static final class Builder {
    //选择平台:Android,java等
    private final Platform platform;
    //okhttp的Call工厂类,Retrofit的网络请求实现委托给okhttp,此工厂类创建出的Call对象就为可以执行网络请求的okhttp3.Call对象。
    private @Nullable okhttp3.Call.Factory callFactory;
    //此为上面使用代码中设置的baseUrl,Builder将我们设置的url封装为HttpUrl对象
    private @Nullable HttpUrl baseUrl;
    //类型转换工厂列表,用于将返回值转换成想要的对象
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    //CallAdapter工厂列表
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    //回调线程池
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;
    ...
    public Builder() {
      this(Platform.get());
    }
}

上面列出了Retrofit.Builder中比较重要的成员变量及方法,其中部分含义已经在注释中写明。其中CallAdapter字面含义“请求适配器”,其具体作用是将网络请求返回值封装成我们想要的形式,比如经常使用的RxJava2CallAdapterFactory便是将返回数据形式封装成Flowable对象来方便进行流式编程,我们也可以自定义CallAdapter,不在本位重点讨论范围之内。先来看Builder() 方法,其只是简单调用了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方法最终调用的是findPlatform方法,根据不同的运行平台来提供不同的线程池。由此可见Builder()方法实际上就行选择了一下平台。
再来看Builder类中converterFactories和callAdapterFactories相关的设置方法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;
    }

可见这两个方法只是简单的将我们自定义的对象分别加入到对应列表中。
继续来看Build模式的最后一步.build()方法,源码如下:

public Retrofit build() {
      //1这一句告诉我们,baseUrl 是必不可少的。
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //2这里如果你没配置 callFactory , 会默认配置为 OkHttpClient
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        //3
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        //4没配置callbackExecutor的话,会默认配置为 Platform 的 defaultCallbackExecutor
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      //5这里会把你所配置的 CallAdapter.Factory 加到 List 里去,最后把 Platform 默认的 defaultCallAdapterFactory加到 List 的最后边
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      //6这里一样会把你配置的 Converter.Factory 加到 List 里去,但是会把一个 BuiltInConverters 加到第一个,再将platform.defaultConverterFactories()加到最后一个,请注意这点。
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      // 先添加BuiltInConverters. 这样不仅防止覆盖其行为并且可以确保使用的所有类型的转换器正确行为。
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      //7
      converterFactories.addAll(platform.defaultConverterFactories());
      //8最后返回一个 Retrofit 对象
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

部分代码作用注释已经给出,通过源码我们可以知道:

  • 注释1处说明我们构建Retrofit对象时baseUrl参数是必传的,不然会报出异常。
  • 注释2和3处说明,如果需要对 OkHttpClient 进行设置,则可以构建 OkHttpClient 对象,然后调用callFactory()方法将设置好的OkHttpClient传进去。如果没有设置callFactory,则直接创建 OkHttpClient。
  • 注释4处的callbackExecutor即回调线程池,作用是将回调传递到 UI 线程,我们可以通过callbackExecutor()方法设置,一般我们使用默认值即可。

下面我们对其中几处进行进一步分析:
先来看看注释4处的platform.defaultCallbackExecutor()是什么,通过前面的build()方法分析可知其主要会根据平台返回一个platform对象,因此在android环境下会返回一个Android()对象。其源码如下:

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环境下构建Retrofit对象时默认的CallbackExecutor对象为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);
  }

可见其默认为DefaultCallAdapterFactory对象转化的列表。
注释7处platform.defaultConverterFactories()的源码为:

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

可见其为空列表。

由注释8可知build() 方法执行完时我们会得到一个Retrofit对象。其构造时将converterFactories和callAdapterFactories封装为了“只读”列表。

第二步:创建网络请求接口实例

得到Retrofit对象和前面定义好的请求接口后我们就可以创建网络请求接口实例了,具体代码如下:

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

这里便体现了Retrofit的核心功能:将一个Java接口翻译成一个Http请求,前面原理部分说过实现这一功能需要通过动态代理。下面我们具体分析源码:

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

可见,其会先去执行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);
        }
      }
    }
  }

根据源码可知该方法前面主要做了一些校验工作,我们重点关注项目注释1处的逻辑,这里用到了我们一直未说明的validateEagerly参数,我们看看其作用是什么,根据源码可知,其逻辑为遍历前面定义好的网络接口方法,然后回去执行loadServiceMethod(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;
  }

这里我们看到一个serviceMethodCache对象,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为一个抽象类,serviceMethodCache 为一个线程安全的、支持高效并发的HashMap,Key 是 Method,Value 是 ServiceMethod。Method 就是上面接口中定义的方法,而这个方法中有很多注解,@GET、@Path 等等,ServiceMethod是将接口定义的方法和注解封装后的对象。而变量名带个 Cache 说明,会把这个 Method 对应的 ServiceMethod缓存起来。

由此可见validateServiceInterface(Class<?> service) 方法中注释1部分整理逻辑为循环取出定义好接口中的 Method ,接着调用 loadServiceMethod 。 loadServiceMethod 里面会根据 Method 生成一个 ServiceMethod,然后存入 serviceMethodCache ,所以那 validateEagerly 变量是用于正如其名字判断是否需要提前验证解析的。如果为true,会提前把接口中每个方法进行解析得到一个 ServiceMethod 对象,然后存入缓存中。

接着回到Retrofit.create()方法后面的代码部分,在执行完 validateServiceInterface(service)方法之后会使用动态代理获取请求接口的所有接口注解配置,并且创建并返回T类型的网络请求接口实例即GitHubService。

第三步:创建Call对象

得到网络请求接口实例后,我们就可以通过动态代理的方式去调用其中的方法,将其转换成对应的网络请求的Call对象实例了。具体示例代码如下:

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

service为前面Retrofit类create()方法创建的接口api的动态代理对象,所以调用其中方法比如service.listRepos("octocat")时会触发代理对象上的invoke方法,再来看Retrofit类create()方法中复写的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方法直接执行
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            //此处为java8方法,android环境下忽略
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            //动态解析网络接口方法并返回
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

通过源码可知其最终会调用loadServiceMethod(method).invoke(args != null ? args : emptyArgs)方法并返回,其中loadServiceMethod(method)前面我们已经提到过,其主要作用就是解析定义好的网络接口,将其中的方法和注释解析并封装成一个ServiceMethod对象并缓存到Map中。现在我们再深入去跟进其中的源码逻辑看看它都具体做了哪些工作,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;
  }

当我们不能从缓存的Map中找到对应方法的缓存时会调用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中可见方法会先创建一个RequestFactory对象,通过它的名字我们猜想到它应该是用来构建网络请求Request对象的,我们来看看这个RequestFactory的源码:

final class RequestFactory {
  //调用parseAnnotations方法最终会通过构建者模式创建一个RequestFactory对象
  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;
...
//该方法用于创建一个okhttp3的网络请求对象Request用于具体实现网络请求
  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();
  }

  /**
   * 检查接口方法上的注释以构造可重用的服务方法。 这个
   *可能需要繁重的反射机制,因此每个服务方法最好只构建一次
   *并重用。 生成器不能重复使用。
   */
  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;
    //方法注解数组
    final Annotation[] methodAnnotations;
    //参数注解二位数组
    final Annotation[][] parameterAnnotationsArray;
    //参数类型数组
    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);
      }
      ...//忽略一堆网络协议规则校验
      
      return new RequestFactory(this);
    }

     //方法主要作用就是解析注解设置成员变量的值
    private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } 
      ...
        isFormEncoded = true;
      }
    }
    //方法主要作用就是解析注解设置成员变量的值
    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);
    }
      //方法主要作用是解析并创建Headers实例
    private Headers parseHeaders(String[] headers) {
      Headers.Builder builder = new Headers.Builder();
      ...
      return builder.build();
    }
    ...
}

代码值列出了部分成员变量,了解retrofit使用方法就能见文知意了解参数含义;列出其中主要的方法并简单加以注释。通过源码我们了解到这个类的主要作用就是去解析第一步创建好的网络请求接口中的方法和注解最终将其转换成okhttp3的网络请求Request对象。
再回到ServiceMethod类的parseAnnotations(Retrofit retrofit, Method method) 中去,再其中注释1解析网络接口并创建好request对象后又在注释2处调用了HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)方法,并将其传了进去。继续跟进源码:

/** 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);
    //此处默认为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协程相关功能,重点关注代码流程,在注释1调用createCallAdapter(retrofit, method, adapterType, annotations)方法,跟踪发现它又会调用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;
      }
    }
  ...
  }

该方法会循环遍历我们之前设置好的callAdapterFactories并注释1处调用其get()方法,由于我们为显示指定CallAdapterFactory前面已经分Retrofit默认会设置为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);
      }
    };
  }

可见其会返回一个CallAdapter对象。其源码先不作分析,接着回到HttpServiceMethod的parseAnnotations源码注释2处,此处调用createResponseConverter ()创建一个Converter对象,其内部流程与callAdapter的创建类似这里就不再做分析了,只是作用为将返回值类型通过此处创建的Conver对象转化为我们想要的数据类型。比如我们再创建Retrofit实例时经常设置的GsonConverterFactory就是讲返回值通过gson解析成想要的实体类。
接着分析HttpServiceMethod的parseAnnotations源码的注释3处,此处调用new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter)方法,并将之前设置的参数全传递了进去,来看源码:

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()中解析网络接口定义并封装成ServiceMethod对象时还做了一下几件事情:

  • 解析网络接口定义,根据方法和注解创建网络请求的request实例;
  • 根据我们设置的CallFactory设置okhttp3的call对象,默认为new OkHttpClient();
  • 根据我们设置的CallAdapterFactory创建好calladapter对象;
  • 根据我们设置的ConverterFactory创建网络返回值转换converter对象;
  • 将所有上面这些对象设置给HttpServiceMethod的成员变量加以管理,等待后续使用。

继续回到Retrofit的create()通过动态代理重写的invoke()源码中,其最终调用loadServiceMethod(method).invoke(args != null ? args : emptyArgs)方法通过前面的分析可知其执行的是HttpServiceMethod的invoke()方法,源码如下:

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

方法创建了一个OkHttpCall对象,通过其名称可知其为okhttp实现的网络请求的具体call对象的封装。通过起源也可发现其集成Call类并在内部维护了整套由okhttp3实现的网络请求功能具体实现及返回数据解析parseResponse()方法的实现其内部通过前面创建的convert对象来解析返回结果。其源码如下:

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 {
      //通过前面创建好并传递过来的converter对象解析返回值
      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;
    }
  }
}

其中正常网络请求的方法为okhttp网络请求实现,源码就不贴了,不了解okhttp网络请求原理的可以去查看我之前发布的okhttp框架源码解析。接着其由调用了adapt(call, args)方法,通过前面分析知其实际调用了其子类CallAdapted的adapt方法,源码如下:

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

通过loadServiceMethod()内部逻辑的分析第三步可知其实际调用的是创建好的calladapter对象的adapte方法,这里再重贴一遍上面为分析完的DefaultCallAdapterFactory get()方法创建的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);
      }
    };
  }

由代码可知,其最终又调用了new ExecutorCallbackCall<>(executor, call)方法,其源码为:

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

功能为给ExecutorCallbackCall类内部成员变量赋值以待后续执行网络请求时使用。由此我们前面的这行代码终于分析完了:

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

其通过动态代理最终得到了一个ExecutorCallbackCall对象实例。并且通过其成员变量名称猜想之后的网络同步异步请求应该是被其delegate成员代理实现的。请求返回的结果的线程切换时由callbackExecutor 处理的。

第四步:通过创建好的由Retrofit封装的Call对象来进行网络通信

Retrofit将Call对象进行了进一步封装,其内部交由OkHttpCall这个实习类来通过okhttp具体实现网络通信。
现在以异步请求为例看一看Retrofit网络请求的实现,通过起那么分析指导enqueue()的代码实现默认其实为ExecutorCallbackCall类的enqueue()方法如下:

@Override public void enqueue(final Callback<T> callback) {
      Objects.requireNonNull(callback, "callback == null");
      // 真正的Call请求确实由delegate(前面分析的OkHttpCall对象)去执行的
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          // 回调后 利用 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 执行了 enqueue 操作,而 delegate 就是我们的 OkHttpCall ,在 OkHttpCall 里的 enqueue 方法是这样工作的。通过 okhttp3.Call call = serviceMethod.toCall(args); 构建一个真正执行请求的 Call ,即把请求交给 okhttp 去完成。而构建一个 Call 利用到了 ServiceMethod 中的 ParameterHandler 对象,这个对象是用来处理参数的。 它会把具体参数的值与 RequestBuilder 绑定起来。当然也用到了 ServiceMethod 自己,ServiceMethod 类似请求响应的大管家。
别忘了拿到响应后,在 okhttp3.Callback 中会去调用 response = parseResponse(rawResponse); 将响应转换成自己想要的格式,即定义的 Converter 。关于返回值得解析在此就不继续解读了,因为不是我们此文的重点。

总结

到此,整个Retrofit的流程终于走完了。简单总结如下:

  1. 通过建造者模式构建一个Retrofit实例,配置baseUrl,callAdapterFactory(将代理返回的Call对象转化为其他,比如Rxjava的Observer),converterFactory(结果的转化器,将请求的结果转化为特定的对象时使用,比如GsonConverterFactory)。
  2. 通过Retrofit对象的create(Class<T> service)方法返回一个Service的动态代理对象,在调用service的方法的时候,就是调用动态代理的invoke方法。
  3. 调用代理的invoke方法的时候,会将网络接口api进行解析,解析我们定义的接口方法以及配置的各种注解,最后构造成ServiceMethod对象,并将结果缓存起来。解析过程中会根据我们的配置创建接口描述的Request对象、CallFactory设置okhttp3的call对象、calladapter对象、converter对象。接着又创建OkHttpCall实例来管理真正的网络实现,然后通过callAdapter转化为用户希望得到的返回对象,默认是直接返回ExecutorCallbackCall对象。
  4. 返回Call对象之后,我们再调用同步execute或者异步enqueue请求,方法内部会通过Okhttp实现的网络请求方法。并根据上一步创建的converter对象将返回数据解析成我们想要的实体类。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容