带你一步步剖析Retrofit 源码解析:一款基于 OkHttp 实现的网络请求框架

OkHttp与Retrofit 的区别与联系是怎样的?git

参考答案:
OkHttp和Retrofit都是目前流行网络开源框架github

封装不一样:
Retrofit封装了具体的请求,线程切换以及数据转换。
retrofit经过使用代理,外观,策略模式对okhttp进行了封装
OkHttp 是基于Http协议封装的一套请求客户端面试

职责不一样:
Retrofit主要负责应用层面的封装,面向开发者,方便使用,好比请求参数,响应数据的处理,错误处理等等。
OkHttp主要负责socket部分的优化与封装,好比网络访问,多路复用,buffer缓存,数据压缩等等。
Android核心技术面试必备.png正则表达式

顺手留下GitHub连接,须要获取相关面试等内容的能够本身去找
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)api

Retrofit 能够说和 OkHttp 是亲兄弟了,它们都是由 Square 公司推出的网络请求库,而且 Retrofit 其实是基于 OkHttp 实现的,它在 OkHttp 现有功能的基础上进行了封装,支持经过注解进行网络请求参数的配置,同时对数据返回后的解析、序列化进行了统一的包装,甚至在近期引入了对协程对支持。缓存

今天就让咱们一块儿来看看 Retrofit 是如何在 OkHttp 这样一个已经固定的框架的基础上,优雅的进行封装并拓展功能的。网络

基本使用
咱们首先来看看 Retrofit 的基本使用,来对它有个大体的了解。app

首先,咱们能够构建一个以下的请求 Service 类,它里面对各个请求的方法及参数经过注解进行了标注:框架

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

以后,咱们能够构建一个 Retrofit 对象,并经过 Retrofit.create 方法传入对应 class 从而构建对应的 Service 对象:异步

Retrofit retrofit = new Retrofit.Builder()
     baseUrl("https://api.github.com/")
     build();
  }
  GitHubService service = retrofit.create(GitHubService.class);

以后,咱们调用 service 中对应的方法,就能够获取到 Call 对象了。

经过对 Call 对象调用 enqueue 就能够实现对请求的异步调用,而经过 execute 方法则能够实现请求的同步调用。

Retrofit 对象的构建

Retrofit 采用了 Builder 模式进行了构建,在 Builder 中能够进行很是多的配置,其中能够对 baseUrlokhttpClientconverterFactorycallAdapterFactory 等进行设置。

这里没什么特别的,都是一些简单的赋值,就再也不关注了,咱们只须要看看最后 Retrofit 被传入了哪些参数。它最后调用了下面这个构造函数对参数进行了初始化。

Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
      @Nullable Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }

Service 对象的建立

动态代理建立 Service 代理类

接着咱们看到本身定义的 interface 是如何仅仅靠传递 classRetrofit.create 就能实现实例的获取的,它明明只是个接口呀?

public <T> T create(final Class<T> service) {
     // 对 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);
            }
            // 若是是对应平台自己的类就有的方法,照常调用
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            // 不然经过 loadServiceMethod 方法获取到对应 Method 并 invoke
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
            }
         });
  }

能够看到,实际上 Service 对象的获取是经过动态代理实现的。这里首先经过 validateServiceInterface 方法对接口进行了检测,以后经过动态代理对该接口进行了代理。

对于 Object 类自己独有以及对应平台自己就存在的方法,就照常调用,不然经过 loadServiceMethodService 中对应的 Method 对象进行处理,以后对其调用 invoke 方法。

这里说明了 Retrofit 不是在建立 Service 接口对应对象时就当即对全部该接口中的全部方法都进行注解的解析,而是采用了在方法被调用时才进行注解的解析这种懒加载的思想。

接着咱们看看 validateServiceInterface 方法:

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());
   }
   // 若是在建立Retrofit时设置了很急切地对Service的方法进行处理,则对非平台独有且非static的方法经过 loadServiceMethod 方法进行处理。
   if (validateEagerly) {
     Platform platform = Platform.get();
     for (Method method : service.getDeclaredMethods()) {
       if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
         loadServiceMethod(method);
       }
     }
   }
  }

首先,这个方法对 service 进行了检测,保证了它是一个接口而且它和它继承的类中没有范型参数。

以后若是在 Retrofit 建立时设置 validateEagerly 为 true 的话,会对 Service 中全部非平台独有且非static的方法经过 loadServiceMethod 方法提早进行处理

Service 中方法的解析

那么咱们来看看 loadServiceMethod 究竟作了些什么:
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;
  }

首先它会采用 Double Check 的方式尝试从 serviceMethodCache 缓存中获取 ServiceMethod 对象,若是获取不到则经过 ServiceMethod.parseAnnotations 方法对该 Method 的注解进行处理并将获得的 ServiceMethod 对象加入了缓存。

也就是说为了不屡次对方法的注解进行处理,Retrofit 采用了一个 serviceMethodCache 对解析后的 ServiceMethod 进行缓存。

接着咱们就来看看,parseAnnotations 方法是如何对方法的注解进行解析的。

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

这里先经过 RequestFactory.parseAnnotations 方法对注解解析并得到了一个 RequestFactory 对象。

以后又经过 HttpServiceMethod.parseAnnotations 方法传入了 requestFactory继续进行注解的解析并得到 ServiceMethod 对象

注解解析

咱们先看看 RequestFactory.parseAnnotations

static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
  return new Builder(retrofit, method).build();
  }

它把 Method 传入 Builder 从而构建了一个新的 RequestFactory

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

Builder 中经过反射获取到method所包含的注解、参数包含的范型以及参数的注解。

接着看看 build 方法:

RequestFactory build() {
    for (Annotation annotation : methodAnnotations) {
        // 遍历方法注解对每一个注解进行解析
      parseMethodAnnotation(annotation);
    }
    // ...异常的处理

   // 对参数进行解析
    int parameterCount = parameterAnnotationsArray.length;
    parameterHandlers = new ParameterHandler<?>[parameterCount];
    for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
      parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
    }

    // ... 异常的处理
   return new RequestFactory(this);
  }

在 build 方法中主要是对方法的每一个注解调用了 parseMethodAnnotation 进行了解析,而且对每一个参数调用了 parseParamter 方法解析为了 ParamterHandler 对象。

parseMethodAnnotation 的代码以下:

private void parseMethodAnnotation(Annotation annotation) {
    if (annotation instanceof DELETE) {
      parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
    } else if (annotation instanceof GET) {
      parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
    } else if (annotation instanceof HEAD) {
      parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
    } else if (annotation instanceof PATCH) {
      parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
    } else if (annotation instanceof POST) {
      parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
    } else if (annotation instanceof PUT) {
      parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
    } else if (annotation instanceof OPTIONS) {
      parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
    } else if (annotation instanceof HTTP) {
      HTTP http = (HTTP) annotation;
      parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
    } else if (annotation instanceof retrofit2.http.Headers) {
      String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
      if (headersToParse.length == 0) {
        throw methodError(method, "@Headers annotation is empty.");
      }
      headers = parseHeaders(headersToParse);
    } else if (annotation instanceof Multipart) {
      if (isFormEncoded) {
        throw methodError(method, "Only one encoding annotation is allowed.");
     }
     isMultipart = true;
    } else if (annotation instanceof FormUrlEncoded) {
      if (isMultipart) {
        throw methodError(method, "Only one encoding annotation is allowed.");
     }
     isFormEncoded = true;
   }
  }

这里实际上就是对每一种 HTTP 所支持的类型进行了支持,获取到了对应注解的中的 url,并调用parseHttpMethodAndPath 进行处理,同时对 Headers 注解则是经过 parseHeaders 进行了处理。

对 Http 请求方式和 Path 的处理

对于 Method 和 Path,经过 parseHttpMethodAndPath 进行了参数的赋值:

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.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(method, "URL query string \"%s\" must not have replace block. "+ "For dynamic query parameters use @Query.", queryParams);
      }
    }
    this.relativeUrl = value;
    this.relativeUrlParamNames = parsePathParameters(value);
  }

这里实际上就是对不一样 HTTP 请求方式和 Path 进行了赋值,同时经过正则表达式保证了这个接口的 Path 中没有包含参数。

对 Headers 的处理

private Headers parseHeaders(String[] headers) {
    Headers.Builder builder = new Headers.Builder();
    for (String header : headers) {
      int colon = header.indexOf(':');
      if (colon == -1 || colon == 0 || colon == header.length() - 1) {
        throw methodError(method,
            "@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
      }
      String headerName = header.substring(0, colon);
      String headerValue = header.substring(colon + 1).trim();
      if ("Content-Type".equalsIgnoreCase(headerName)) {
        try {
          contentType = MediaType.get(headerValue);
        } catch (IllegalArgumentException e) {
          throw methodError(method, e, "Malformed content type: %s", headerValue);
        }
      } else {
        builder.add(headerName, headerValue);
      }
    }
    return builder.build();
  }

而对于 Headers 则是将传递进来的 Headers 列表解析为了对应的 Headers 对象。

对方法参数的处理
最后咱们看看对方法参数的处理:
private @Nullable ParameterHandler<?> parseParameter(
      int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
    ParameterHandler<?> result = null;
    if (annotations != null) {
      for (Annotation annotation : annotations) {
          // 对每一个注解经过 parseParameterAnnotation 进行解析
        ParameterHandler<?> annotationAction =
            parseParameterAnnotation(p, parameterType, annotations, annotation);
        if (annotationAction == null) {
          continue;
        }
        if (result != null) {
          throw parameterError(method, p,
              "Multiple Retrofit annotations found, only one allowed.");
        }
        result = annotationAction;
      }
    }
    if (result == null) {
        // 在协程的状况下对进行特殊处理
      if (allowContinuation) {
        try {
          if (Utils.getRawType(parameterType) == Continuation.class) {
            isKotlinSuspendFunction = true;
            return null;
          }
        } catch (NoClassDefFoundError ignored) {
        }
      }
      throw parameterError(method, p, "No Retrofit annotation found.");
    }
    return result;
  }

parseParamterAnnotation 方法的代码太长了,这里就再也不贴了,它对方法的每一个注解都进行了独有的处理,并返回了对应的 ParamterHandler

能够发现,RequestFactory.parseAnnotations 的主要做用就是完成对方法注解信息的解析,从而用于产生对应的 Request

ServiceMethod 的建立

以后咱们接着看看 HttpServiceMethod.parseAnnotations
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) {
        // 若是方法是 kotlin 中的 suspend 方法
      Type[] parameterTypes = method.getGenericParameterTypes();
      // 获取 Continuation 的范型参数,它就是 suspend 方法的返回值类型
      Type responseType = Utils.getParameterLowerBound(0,
          (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      // 若是 Continuation 的范型参数是 Response,则说明它须要的是 Response,那么将 continuationWantsResponse 置为 true;
      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();
    }
    // 经过 createCallAdapter 方法建立 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.");
    }
    // 经过 createResponseConverter 方法建立 Converter对象
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
        // 不是suspend方法的话则直接建立并返回一个 CallAdapted 对象
      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. 若是这个方法是 Kotlin 中的 suspend 方法,因为由协程实现,所以须要获取 Continuation 的范型参数,这个参数就是请求返回值的真正类型。
2. 若是 suspend 方法返回值是 Response,则说明它须要的是 Response 而不是具体的类型,那么将 continuationWantsResponse 置为 true;
3. 若是不是 suspend 方法,则返回值的范型参数的类型就是请求返回值的真正类型(Call&lt;ReturnType&gt;ReturnType 才是真正通过转换后须要的类型)。
4. 经过 createCallAdapter 方法建立 CallAdapter 对象,它是用于将 Call&lt;ResponseT&gt; 对象适配为须要的类型 ReturnT 对象的。
5. 拿到 CallAdapter 后,获取到了 Response 的类型,并进行了校验。
6. 经过 createResponseConverter 方法获取 Converter 对象,它能够完成从 ResponseBodyResponse 类型 ResponseT 的转换。
7. 若是并不是 Kotlin 的 suspend 方法,则直接传入 CallAdapter 及 Converter,建立 CallAdapted 对象。
8. 不然根据 suspend 方法须要的是 Response 仍是具体的类型,分别返回 SuspendForResponseSuspendForBody 对象。

能够发现,新版的 Retrofit 对 Kotlin 的协程进行了支持。HttpServiceMethod.parseAnnotations 的主要做用就是建立 CallAdapter 以及 Converter 对象,并构建对应 HttpServiceMethod

CallAdapter

CallAdapter 是用于将Call&lt;R&gt;对象适配为须要的类型 T 对象的。它的声明以下:

public interface CallAdapter<R, T> {

      // 返回 Response 的类型
    Type responseType();
       // 将 Call<R> 转换为 T 类型 
    T adapt(Call<R> call);
  }

咱们先看看 createCallAdapter 方法是如何对它建立的:

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

它调用了 retrofit.callAdapter 方法:

public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

以后调用到 retrofit.nextCallAdapter 方法:

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    Objects.requireNonNull(returnType, "returnType == null");
    Objects.requireNonNull(annotations, "annotations == null");
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
         // 遍历 callAdapterFactories,尝试建立 CallAdapter
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
    // ...不存在对应的 CallAdapterFactory,抛出异常
  }

这里其实是遍历了建立 Retrofit 对象时传递的 CallAdapter.Factory 列表尝试去建立 CallAdapter。若是这些 CallAdapter.Factory 都没法处理这个对应的 returnType 以及 annotations 的话,则会抛出异常。(前面 Factory 的优先级更高)

Retrofit 中有一个默认的 CallAdapter 工厂 DefaultCallAdapterFactory它的优先级比全部自定义工厂要低,它在建立时会传入一个 Executor,咱们能够看到它的 get 方法:

@Override public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    if (!(returnType instanceof ParameterizedType)) {
      throw new IllegalArgumentException(
          "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
    }
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
    final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
        ? null: callbackExecutor;
    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);
      }
    };
  }

能够看到,在没有 Executor 时,它不对 Call 进行修改,在有指定 Executor 时,则会将其包装为 ExecutorCallbackCall。通常来讲这个 Executor 就是建立 Retrofit 时指定的 callbackExecutor

这个 callbackExecutor 其实是用来指定调用 Callback 的线程的,从而使得 Callback 并不必定是在主线程被回调:

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

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

    @Override public void enqueue(final Callback<T> callback) {
      Objects.requireNonNull(callback, "callback == null");
      // 对 Callback 进行了包装,经过 callbackExecutor 进行回调
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          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));
        }
      });
    }
    // ...
  }

能够看到,这里实际上只是对 Callback 进行了包装,经过传递的 Executor 进行回调,从而对 callbackExecutor 进行支持。

Converter

接着咱们看看 Converter 类,它是一个接口,用于将类型 F 的数据转换为类型 T:

public interface Converter<F, T> {
    @Nullable T convert(F value) throws IOException;
       // ...
  }

接着咱们看看 createResponseConverter 是如何对它进行建立的:

private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
      Retrofit retrofit, Method method, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
    try {
      return retrofit.responseBodyConverter(responseType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create converter for %s", responseType);
    }
  }

转调到了 retrofit.responseBodyConverter

public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
  }

转调到了 nextResponseBodyConverter

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    Objects.requireNonNull(type, "type == null");
    Objects.requireNonNull(annotations, "annotations == null");
    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }
    // 没有找到对应的 ConverterFactory 进行处理,抛出异常
  }

能够看到,这里与 CallAdapter 工厂相似,遍历建立 Retrofit 时传入的 Converter.Factory 列表,尝试进行建立,若是没有工厂能对其进行处理,抛出异常。(前面 Factory 的优先级更高)

Retrofit 中内置了两个 Converter.Factory,分别是 BuiltInConverters 以及 OptionalConverterFactory

其中 BuiltInConverters 的优先级比全部自定义工厂要高,以免其余工厂覆盖它的方法,而 OptionalConverterFactory的优先级比全部自定义工厂的优先级更低。

BuiltInConverters 中实现了多个转换器如将 ResponseBody 转换为 Void 或 Unit,将 Object 转换为 String 等。

OptionalConverterFactory是经过 platform 获取到的 defaultConverterFactories,它是为了支持 Java 8 的 Optional 而实现的,Optional 是 Java 8 引入的用来解决空指针异常的类。

ServiceMethod

接着咱们看看以前建立的 ServiceMethod 类,它是一个抽象类,须要子类对 invoke 方法进行实现。

abstract class ServiceMethod<T> {
    abstract @Nullable T invoke(Object[] args);
  }

它的子类就是前面提到的 HttpServiceMethod

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

    protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
  }

HttpServiceMethod 的 invoke 方法很是简单,它构造了一个 OkHttpCall,而后经过 adapt 这个虚函数来实现对 Call 的转换。它的子类只须要实现 adapt 从而对 Call 进行转换便可。

它共有三个子类,首先就是并不是使用协程的状况下的 CallAdapted 类,另外两个子类则是在使用协程的状况下为了配合协程的 SuspendForResponse 以及 SuspendForBody

CallAdapted

CallAdapted 类继承自 HttpServiceMethod 类,并经过传递进来的 CallAdapter 对 Call 进行了转换。

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;

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

SuspendForResponse

SuspendForResponse 类首先根据传递进来的 Call 构造了一个参数为 Response&lt;ResponseT&gt;Continuation 对象而后经过 Kotlin 实现的 awaitResponse 方法将 call 的 enqueue 异步回调过程封装为了一个 suspend 的函数。

static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
    private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
    SuspendForResponse(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, Call<ResponseT>> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }

    @Override protected Object adapt(Call<ResponseT> call, Object[] args) {
      call = callAdapter.adapt(call);
      //noinspection unchecked Checked by reflection inside RequestFactory.
      Continuation<Response<ResponseT>> continuation =
          (Continuation<Response<ResponseT>>) args[args.length - 1];
      // See SuspendForBody for explanation about this try/catch.
      try {
        return KotlinExtensions.awaitResponse(call, continuation);
      } catch (Exception e) {
        return KotlinExtensions.suspendAndThrow(e, continuation);
      }
    }
  }

awaitResponse 方法以下:

suspend fun <T : Any> Call<T>.awaitResponse(): Response<T> {
    return suspendCancellableCoroutine { continuation ->
      continuation.invokeOnCancellation {
        cancel()
      }
      enqueue(object : Callback<T> {
        override fun onResponse(call: Call<T>, response: Response<T>) {
          continuation.resume(response)
        }
        override fun onFailure(call: Call<T>, t: Throwable) {
          continuation.resumeWithException(t)
        }
      })
    }
  }

能够看到,分别经过在 onResponseonFailure 中调用 continuation.resumecontinuation.resumeWithException从而对协程进行支持。

SuspendForBody

SuspendForBody 则是根据传递进来的 Call 构造了一个 Continuation&lt;ResponseT&gt; 对象而后经过 Kotlin 实现的 await 或 awaitNullable 方法将 call 的 enqueue 异步回调过程封装为了一个 suspend 的函数。

static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
    private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
    private final boolean isNullable;
    SuspendForBody(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, Call<ResponseT>> callAdapter, boolean isNullable) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
      this.isNullable = isNullable;
    }
    @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];
      // Calls to OkHttp Call.enqueue() like those inside await and awaitNullable can sometimes
      // invoke the supplied callback with an exception before the invoking stack frame can return.
      // Coroutines will intercept the subsequent invocation of the Continuation and throw the
      // exception synchronously. A Java Proxy cannot throw checked exceptions without them being
      // in an UndeclaredThrowableException, it is intercepted and supplied to a helper which will
      // force suspension to occur so that it can be instead delivered to the continuation to
      // bypass this restriction.
      try {
        return isNullable
            ? KotlinExtensions.awaitNullable(call, continuation)
            : KotlinExtensions.await(call, continuation);
      } catch (Exception e) {
        return KotlinExtensions.suspendAndThrow(e, continuation);
      }
    }
  }

Call

Call 其实是一个接口,它提供了 executeenqueuecancel 等接口用于实现请求,当咱们须要请求一个接口的时候,只须要调用其 enqueueexecute方法便可。

public interface Call<T> extends Cloneable {

    Response<T> execute() throws IOException;

    void enqueue(Callback<T> callback);

    boolean isExecuted();

    void cancel();

    boolean isCanceled();

    Call<T> clone();

    Request request();
  }

从前面的过程当中咱们能够了解到,若是咱们没有传入 CalAdapter 的话,默认状况下返回的 Call 其实是 OkHttpCall 对象,让咱们经过它来看看 Retrofit 如何基于 OkHttp 实现的网络请求:

enqueue

首先让咱们看看 enqueue 的代码:

@Override public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(callback, "callback == null");
    okhttp3.Call call;
    Throwable failure;
    // 加锁,对状态进行设置并经过 createRawCall 方法建立 okhttp3.Call
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }
    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }
    // 若是外界取消该任务,则调用 okhttp3.Call.cancel
    if (canceled) {
      call.cancel();
    }
    // 经过 okhttp3.Call.enqueue 将消息入队
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
          try {
            // 得到结果后经过 parseResponse 进行解析
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          throwIfFatal(e);
          callFailure(e);
          return;
        }
        try {
            // 解析完成后经过 onResponse 进行回调
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }
      @Override public void onFailure(okhttp3.Call call, IOException e) {
          // 请求失败调用 callFailure 回调失败请求
        callFailure(e);
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }
    });
  }

enqueue 的代码看似多,实际上比较简单,主要分为如下几步:

1. 加锁,对执行状态进行设置,若不存在 rawCall 则调用 createRawCall 方法建立 okhttp3.Call 对象。
2. 若是外界取消该任务,则调用 okhttp3.Call.cancel
3. 经过 okhttp3.Call.enqueue 将消息入队
4. 若得到 Response,则经过 parseResponse 方法对 Response 进行解析,解析完成后经过 onResponse 回调解析结果。
5. 若请求失败,经过 callFailure 方法调用 onFailure 回调请求失败。

能够发现一个小细节,Retrofit 对已经建立的 okhttp3.Call 进行了复用,避免了重复建立从而浪费效率。

execute

接着让咱们看看 execute 是如何实现的:

@Override public Response<T> execute() throws IOException {
    okhttp3.Call call;
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      if (creationFailure != null) {
        if (creationFailure instanceof IOException) {
          throw (IOException) creationFailure;
        } else if (creationFailure instanceof RuntimeException) {
          throw (RuntimeException) creationFailure;
        } else {
          throw (Error) creationFailure;
        }
      }
      call = rawCall;
      if (call == null) {
        try {
          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();
    }
    return parseResponse(call.execute());
  }

也很是简单:

1.首先加锁后对执行状态进行设置,若不存在 rawCall 则调用 createRawCall方法建立 okhttp3.Call 对象。
2.若是外界取消该任务,则调用 okhttp3.Call.cancel
3.若得到 Response,则经过 parseResponse 方法对 Response 进行解析并返回

okhttp3.Call 的建立

接着让咱们看看 createRawCall 方法:

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

它其实是调用了 callFactorynewCall 方法进行建立,而传入的 okhttp3.Request 则是经过 requestFactory.create 建立的:

okhttp3.Request create(Object[] args) throws IOException {
    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
    int argumentCount = args.length;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount+ ") doesn't match expected count (" + handlers.length + ")");
    }
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart);
    if (isKotlinSuspendFunction) {
      // The Continuation is the last parameter and the handlers array contains null at that index.
      argumentCount--;
    }
    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();
  }

这里首先构建了一个 RequestBuilder,以后经过遍历 ParamterHandler 列表并调用其 apply 方法将参数应用到 RequestBuilder 中。

parseResponse

接着咱们看看 parseResponse 是如何对 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();
    // ...
    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
      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;
    }
  }

能够看到,它会经过 Converter.convert 方法将 Response 的 body 转换为咱们所须要的类型。

总结

那么到这里,Retrofit的源码咱们就基本上看完了,能够发现它的代码中基本不多涉及到对网络请求的处理,基本都是对于 OkHttp 的封装,在 OkHttp 现有的 API 上提供了一套更便于使用的框架。

Retrofit 很好地向咱们证实了,如何在一套已经固定的 API 上,以最优雅的方式对现有的框架进行封装,拓展出更为强大的功能。

Retrofit 的注解是一种运行时注解,它经过动态代理对 Service 对象进行建立,经过反射对注解进行解析,这样虽然会有必定性能的损耗,但性能的损耗却带来了十分易用的 API。用户所写的 Service 接口中,每个 ServiceMethod都对应了一个接口。

对于 Service 的建立,它是经过动态代理,对每一个接口内定义的方法进行了代理,若设置 validateEagerly了则会在建立 Service 接口对象时进行注解的解析以及 ServiceMethod 的建立,不然会在方法调用时再建立对应的 ServiceMethod 对象,在屡次调用的状况下,它经过 serviceMethodCache 对已经解析的 ServiceMethod 进行了缓存从而避免了重复解析带来的性能损耗。

这个对象的建立首先会通过 RequestFactory.parseAnnotations 对方法中的注解进行解析:

  • 对于方法的请求方式注解,它会经过 parseHttpMethodAndPath 方法获取注解对应的请求方式以及注解中的 url 等信息并保存起来,在建立请求的时候设置进 RequestBuilder
  • 对于方法的 Headers 注解,它会将 Header 注解解析为 Headers 对象并保存起来,在建立请求的时候设置进 RequestBuilder
  • 对于方法的参数,它会将每一个参数根据具体的注解(@Query 等)解析为对应的 ParamterHandler,在建立请求的时候,会经过它的 apply 方法将参数提交到 RequestBuilder 中。

以后,这个对象会经过 HttpServiceMethod.parseAnnotationsServiceMethod 对象进行建立,它在建立的过程当中同时进行了接口对应的 CallAdapter 以及 Converter 的建立。

其中,CallAdapter 用于将Call&lt;R&gt; 对象适配为须要的类型 T 对象,也就是对 Call 进行转换。

Converter 则是用于将 F 类型的数据转换为 T,每每是用于对 Response的 body 进行转换。

对于 CallAdapterConverter 都是经过它们对应的工厂类进行建立,建立时会根据工厂列表的顺序从前向后尝试进行建立,也就是说在工厂列表中越靠前的工厂其优先级越大。

同时,Retrofit 还引入了对 Continuation 协程的支持,它会将 ServerMethod 最终包装为一个 suspend 方法从而对协程进行支持。

Retrofit的网络请求的执行依赖于 OkHttp,它首先会经过 RequestFactory 进行 Request 的构造,它的参数经过前面解析的信息得来。以后会将这个 Request 包装为一个 okhttp3.Call,在同步和异步请求时分别调用其对应的 execute 及 enqueue 方法。同时,为了不okhttp3.Call 的重复建立,它对以前建立的 okhttp3.Call 进行了复用。

顺手留下GitHub连接,须要获取相关面试等内容的能够本身去找
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)

相关文章
相关标签/搜索