Retrofit源码分析

栏目: IOS · Android · 发布时间: 4年前

内容简介:上篇文章简单分析了OkHttp的源码,本篇文章来分析下Retrofit的源码实现,从Retrofit的简单使用方式出发首先需要定义一个网络请求的API接口,内部配合注解声明了请求方法、请求地址等信息,然后需要创建Retrofit实例,接着调用其create方法创建一个API接口实现类的一个实例,然后就可以通过调用该实例的指定方法拿到Call实例,接下来就和OkHttp的使用方式没有什么不同了接下来按照Retrofit实例的创建、retrofit.create方法的调用、api.inTheater方法的调用、

上篇文章简单分析了OkHttp的源码,本篇文章来分析下Retrofit的源码实现,从Retrofit的简单使用方式出发

一、简单使用

首先需要定义一个网络请求的API接口,内部配合注解声明了请求方法、请求地址等信息,然后需要创建Retrofit实例,接着调用其create方法创建一个API接口实现类的一个实例,然后就可以通过调用该实例的指定方法拿到Call实例,接下来就和OkHttp的使用方式没有什么不同了

interface DoubanAPI {
    @GET("v2/movie/in_theaters")
    fun inTheaters(@Query("start") start: Int) : Call<ResponseBody>
}
fun main() {
    val retrofit = Retrofit.Builder()
            .baseUrl("https://api.douban.com/")
            .validateEagerly(true)
            .build()
    val api = retrofit.create(DoubanAPI::class.java)
    val call = api.inTheaters(10)
    val response = call.execute()
    if (response.isSuccessful) {
        println("请求成功: ${response.body()!!.string()}")
    } else {
        println("请求失败: ${response.message()}")
    }
}
复制代码

接下来按照Retrofit实例的创建、retrofit.create方法的调用、api.inTheater方法的调用、call.execute方法的调用来分析Retrofit的源码。

二、Retrofit实例的构建

这里使用了建造者模式构建Retrofit实例因此首先看看Builder的构造方法

public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private @Nullable HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;
    Builder(Platform platform) {
        this.platform = platform;
    }
    public Builder() {
        // 通过反射来判断是Android还是 Java 8
        this(Platform.get());
    }
}
复制代码

接着又调用了baseUrl方法用来设置当前Retrofit的baseUrl

public Builder baseUrl(String baseUrl) {
    checkNotNull(baseUrl, "baseUrl == null");
    return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
    checkNotNull(baseUrl, "baseUrl == null");
    List<String> pathSegments = baseUrl.pathSegments();
    // 要求baseUrl必须要以/结尾
    if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
    }
    this.baseUrl = baseUrl;
    return this;
}
复制代码

然后我们就直接执行build方法构造Retrofit实例

public Retrofit build() {
    // baseUrl是必须的,就算没用也得设置一个
    if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
    }
    okhttp3.Call.Factory callFactory = this.callFactory;
    // 如果没有设置callFactory就设置一个OkHttpClient实例赋值给callFactory
    if (callFactory == null) {
        callFactory = new OkHttpClient();
    }
    Executor callbackExecutor = this.callbackExecutor;
    // 如果没有设置callbackExecutor就设置,如果是Android会设置一个MainThreadExecutor,用于将回调切换到主线程执行
    if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
    }
    // 将外界添加的CallAdapter.Factory与系统自带的CallAdapter.Factory合并,比如RXjava提供的RxJava2CallAdapterFactory,注意用户的优先
    List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
    // 在Android中如果API>=24会拥有CompletableFutureCallAdapterFactory、ExecutorCallAdapterFactory两个实例
    callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
    // 添加ConvertFactory,API24会默认拥有BuiltInConverters、OptionalConverterFactory
    List<Converter.Factory> converterFactories = new ArrayList<>(
            1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
    converterFactories.add(new BuiltInConverters());
    converterFactories.addAll(this.converterFactories);
    converterFactories.addAll(platform.defaultConverterFactories());
    // 其中validateEagerly表示是否急切的验证方法的合法性
    return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
            unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
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;
}
复制代码

到此为止Retrofit实例已经创建完毕,接下来看看其create方法

三、retrofit.create方法的调用

create方法内部做的事情主要有注解解析,动态代理,先来看看注解解析过程

注解解析

public <T> T create(final Class<T> service) {
    // 判断下传入的Class实例是否是接口,并且判断其是否继承了其它接口
    Utils.validateServiceInterface(service);
    // 如果该属性为true,在create方法执行的时候就会检查接口方法的合法性,不然要等到调用指定方法的时候才会检查
    if (validateEagerly) {  
        eagerlyValidateMethods(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 Object invoke(Object proxy, Method method, @Nullable Object[] args)
                throws Throwable {
            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);
          }
        });
}
private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
        // 如果不是默认方法就执行加载
        if (!platform.isDefaultMethod(method)) {
            loadServiceMethod(method);
        }
    }
}
ServiceMethod<?> loadServiceMethod(Method method) {
    // 从缓存中取,取到就直接返回(eagerlyValidateMethods是取不到的)
    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;
}
复制代码

接着调用了parseAnnotations用于解析接口中每一个方法上的注解

// ServiceMethod.java
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.java
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
}
// 读取了方法的注解,方法参数类型,方法参数注解
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);
    }
    // 必须要有请求方法不然抛出错误
    if (httpMethod == null) {
        throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
    }
    // 如果这个请求不需要有请求体(根据请求方法判断),但是设置了Multipart或者isFormEncoded就抛出错误
    if (!hasBody) {
        if (isMultipart) {
          throw methodError(method,
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
            throw methodError(method, "FormUrlEncoded can only be specified on HTTP methods with "
                + "request body (e.g., @POST).");
            }
        }
    }
    // 获取方法参数数量
    int parameterCount = parameterAnnotationsArray.length;
    parameterHandlers = new ParameterHandler<?>[parameterCount];
    for (int p = 0; p < parameterCount; p++) {
        parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
    }
    if (relativeUrl == null && !gotUrl) {
        throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
    }
    if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError(method, "Non-body HTTP method cannot contain @Body.");
    }
    if (isFormEncoded && !gotField) {
        throw methodError(method, "Form-encoded method must contain at least one @Field.");
    }
    if (isMultipart && !gotPart) {
        throw methodError(method, "Multipart method must contain at least one @Part.");
    }
    return new RequestFactory(this);
}
复制代码

build方法内部又分别解析了每个方法上面的注解和每个方法参数上面的注解

1. 解析方法上的注解

来看看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;
    }
}
复制代码

该方法解析了所有接口方法上面的注释,其中Mutipart、FormUrlEncoded这里处理比较简单就是两者不能共存,DELETE、GET、HEAD、PATCH、POST、PUT、OPTIONS处理方式都一样都是直接调用了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;
    }
    // 如果url中包含?号那么就相当于有请求参数
    int question = value.indexOf('?');
    if (question != -1 && question < value.length() - 1) {
        // 将查询参数字符串切割出来
        String queryParams = value.substring(question + 1);
        // 查询参数里面不允许使用{参数}的方式,取代方法是使用@Query注解
        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;
    // 将url中的{参数}找出来
    this.relativeUrlParamNames = parsePathParameters(value);
}
static Set<String> parsePathParameters(String path) {
    Matcher m = PARAM_URL_REGEX.matcher(path);
    Set<String> patterns = new LinkedHashSet<>();
    while (m.find()) {
    	patterns.add(m.group(1));
    }
    return patterns;
}
复制代码

然后看看HTTP注解的解析过程,与GET相比起不同点只在于parseHttpMethodAndPath的方法入参都是从注解实例中取出,我们可以这么定义HTTP注解

interface DoubanAPI {
    @HTTP(method = "GET", path = "v2/movie/in_theaters")
    fun inTheaters() : Call<ResponseBody>
}
复制代码

接着看看Headers注解的解析,首先判断了Headers注解的值是否设置,如果没设置就抛出错误,然后调用parseHeaders进行解析

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();
}
复制代码

可以看到parseHeaders内部其实就是根据冒号分割每个字符串,然后将其放入到Header.Builder实例中统一管理,接下来看看方法参数的解析

2. 解析方法参数上的注解

RequestFactory.Builder的build方法中在解析完方法上面注解后,又会调用到parseParameter解析方法每个参数上的注解,注意虽然每个参数可以有多少注解,但是每个参数只能拥有一个Retrofit注解

// 其中p指代该参数是方法的第几个参数,parameterTypes[p]表示当前参数的参数类型,
// parameterAnnotationsArray[p]表示当前参数的注解是个数组
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);

private ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations) {
    ParameterHandler<?> result = null;
    if (annotations != null) {
        for (Annotation annotation : annotations) {
            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;
        }
    }
    // 方法的每个参数都必须有且仅有一个Refrofit注解
    if (result == null) {
        throw parameterError(method, p, "No Retrofit annotation found.");
    }
    return result;
}
复制代码

接着又调用到了parseParameterAnnotation这个方法非常长有400行左右,就不展开了只是说说其大概做了些什么. 注意里面判断了一个不常用的注解@QueryName这个注解表示在Url后面拼加一个只有name没有value的字符串

  • @Url,则需要确保以下几点,最终会创建一个ParameterHandler.RelativeUrl实例返回
  1. 不能出现多个@Url注解
  2. @Url不能和@Path共存
  3. @Url不能声明在@Query后
  4. @Url不能声明在@QueryName后
  5. @Url不能声明在@QueryMap后
  6. @Url使用了就不能再在请求方法后面加上相对地址
  7. 检测参数类型必须是HttpUrl、String、URI、Uri中的一种不然抛出错误
  • @Path,则需要确保以下几点,最终会创建一个ParameterHandler.Path实例返回
  1. @Path不能声明在@Query后面
  2. @Path不能声明在@QueryName后面
  3. @Path不能声明在@QueryMap后面
  4. @Path不能和@Url共存
  5. @Path使用了就必须要在请求方法后面加上相对地址
  6. 刚才解析方法上Url的时候会把所有{参数}解析出来放到relativeUrlParamNames这个Set中去,如果这个集合中不存在Path.value就会报错
  • @Query,则会根据参数类型最终返回ParameterHandler.Query<>(name, converter, encoded).iterable()、ParameterHandler.Query<>(name, converter, encoded).array()、ParameterHandler.Query<>(name, converter, encoded)三者之一,就这告诉我们@Query修饰的参数类型可以是一个容器或者数组,如下所示

    interface DoubanAPI {
        @GET("v2/movie/in_theaters")
        fun inTheaters(@Query("keyword") List<String> keywords) : Call<ResponseBody>
    }
    val list = ArrayList<String>()
    list.add("keyword1")
    list.add("keyword2")
    val api = retrofit.create(DoubanAPI::class.java)
    val call = api.inTheaters(list)
    // 最终的url为https://api.douban.com/v2/movie/in_theaters?keyword=keyword1&keyword=keyword2
    复制代码
  • @QueryName,则会根据参数类型最终返回ParameterHandler.QueryName<>(converter, encoded).iterable()、ParameterHandler.QueryName<>(converter, encoded).array()、ParameterHandler.QueryName<>(converter, encoded)三者之一,跟@Query基本一样

  • @QueryMap,首先会检查下参数类型是否是Map,然后还会检查下Map的key是否是String,最后会封装成ParameterHandler.QueryMap返回

  • @Header,最终也会根据参数类型转换为ParameterHandler.Header<>(name, converter).iterable()、ParameterHandler.Header<>(name, converter).array()、ParameterHandler.Header<>(name, converter)之一,这里也能看出@Header注解支持容器(内部类型要是String)或者数组

  • @HeaderMap,解析步骤和@QueryMap一样,最后返回ParameterHandler.HeaderMap

  • @Field 首先会检查是否已经设置了FormUrlEncoded,没设置就报错也会根据参数类型最后返回ParameterHandler.Field<>(name, converter, encoded).iterable()、ParameterHandler.Field<>(name, converter, encoded).array()、ParameterHandler.Field三者之一

  • @FieldMap 与@QueryMap判断一致最后会返回一个ParameterHandler.FieldMap实例

  • @Part 首先检查是否设置了Multipart注解,没设置就报错,然后判断注解的value属性是否为空,接着根据类型返回ParameterHandler.RawPart.INSTANCE.iterable()、ParameterHandler.RawPart.INSTANCE.array()、ParameterHandler.RawPart.INSTANCE之一,如果value属性不为空会先添加几个Header,然后根据类型返回ParameterHandler.Part<>(headers, converter).iterable()、ParameterHandler.Part<>(headers, converter).array()、ParameterHandler.Part<>(headers, converter)

  • @PartMap 与@QueryMap判断基本一致,最终返回ParameterHandler.PartMap

  • @Body 如果设置了@FormUrlEncoded或者@Multipart就报错,否则返回一个ParameterHandler.Body实例

至此方法上面和请求参数上面的注解已经都解析完毕了

HttpServiceMethod实例的生成

接着调用HttpServiceMethod.parseAnnotations获取ServiceMethod实例将其放入到serviceMethodCache中

// HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
            Retrofit retrofit, Method method, RequestFactory requestFactory) {
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
    Type responseType = callAdapter.responseType();
    if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError(method, "'"
                + Utils.getRawType(responseType).getName()
                + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
        throw methodError(method, "HEAD method must use Void as response type.");
    }
    Converter<ResponseBody, ResponseT> responseConverter =
            createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
复制代码

获取CallAdapter实例

然后调用到了createCallAdapter用于获取能处理该返回类型的CallAdapter

private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method) {
    Type returnType = method.getGenericReturnType();
    Annotation[] annotations = method.getAnnotations();
    try {
        return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) {
        throw methodError(method, e, "Unable to create call adapter for %s", returnType);
    }
}
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
  Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
        CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
        if (adapter != null) {
            return adapter;
        }
    }
    StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
        .append(returnType)
        .append(".\n");
    if (skipPast != null) {
        builder.append("  Skipped:");
        for (int i = 0; i < start; i++) {
            builder.append("\n   * ").append(callAdapterFactories.get(i).getClass().getName());
        }
        builder.append('\n');
    }
    builder.append("  Tried:");
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
        builder.append("\n   * ").append(callAdapterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
}
复制代码

可以看出nextCallAdapter会在Retrofit的callAdapterFactories里面遍历查找能处理该返回类型的CallAdapter,而callAdapterFactories在文章一开始已经说过了API24及以上默认包含 CompletableFutureCallAdapterFactoryDefaultCallAdapterFactory 两个CallAdapterFactory,也就是说默认方法返回值只能是 CompletableFuture 或者 retrofit2.Call ,其余都将报错

获取Converter实例

HttpServiceMethod.parseAnnotations后面接着又会调用createResponseConverter获取Convert实例

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);
    }
}
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
            @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(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) {
            return (Converter<ResponseBody, T>) converter;
        }
    }
    StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
            .append(type)
            .append(".\n");
    if (skipPast != null) {
        builder.append("  Skipped:");
        for (int i = 0; i < start; i++) {
            builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
        }
        builder.append('\n');
    }
    builder.append("  Tried:");
    for (int i = start, count = converterFactories.size(); i < count; i++) {
        builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
}
复制代码

跟获取CallAdapter流程基本一样,其会在converterFactories里面遍历寻找是否有Convert可以将ResponseBody转化为type类型,API>=24会默认拥有BuiltInConverters、OptionalConverterFactory两个ConvertFactory,首先看看BuiltInConverters

BuiltInConverters

// BuiltInConverters.java
final class BuiltInConverters extends Converter.Factory {
    private boolean checkForKotlinUnit = true;
    @Override
    public @Nullable
    Converter<ResponseBody, ?> responseBodyConverter(
            Type type, Annotation[] annotations, Retrofit retrofit) {
        if (type == ResponseBody.class) {
            return Utils.isAnnotationPresent(annotations, Streaming.class)
                    ? StreamingResponseBodyConverter.INSTANCE
                    : BufferingResponseBodyConverter.INSTANCE;
        }
        if (type == Void.class) {
            return VoidResponseBodyConverter.INSTANCE;
        }
        if (checkForKotlinUnit) {
            try {
                if (type == Unit.class) {
                    return UnitResponseBodyConverter.INSTANCE;
                }
            } catch (NoClassDefFoundError ignored) { 
                checkForKotlinUnit = false;
            }
        }
        return null;
    }
}
static final class StreamingResponseBodyConverter
        implements Converter<ResponseBody, ResponseBody> {
    static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();
    @Override
    public ResponseBody convert(ResponseBody value) {
        return value;
    }
}
static final class BufferingResponseBodyConverter
            implements Converter<ResponseBody, ResponseBody> {
    static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
    @Override
    public ResponseBody convert(ResponseBody value) throws IOException {
        try {
            // 全部读入内存
            return Utils.buffer(value);
        } finally {
            value.close();
        }
    }
}
static ResponseBody buffer(final ResponseBody body) throws IOException {
    Buffer buffer = new Buffer();
    // 将body的内容全部读入到buffer中去
    body.source().readAll(buffer);
    return ResponseBody.create(body.contentType(), body.contentLength(), buffer);
}
static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {
        static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();
    @Override
    public Void convert(ResponseBody value) {
        value.close();
        return null;
    }
}
复制代码
  • 如果目标转化类型为ResponseBody并且方法上有@Stream注解,那么会原封不动的返回
  • 如果目标转化类型为ResponseBody并且方法上没有@Stream注解,那么会将ResponseBody整个读入内存(注意当文件过大可能会OOM)
  • 如果目标转化类型为Void,那么将ResponseBody直接关闭,外界拿到的响应体就是null
  • 如果目标转化类型为Unit,那么跟Void一样

OptionalConverterFactory

final class OptionalConverterFactory extends Converter.Factory {
    static final Converter.Factory INSTANCE = new OptionalConverterFactory();
    @Override
    public @Nullable
    Converter<ResponseBody, ?> responseBodyConverter(
            Type type, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(type) != Optional.class) {
            return null;
        }
        Type innerType = getParameterUpperBound(0, (ParameterizedType) type);
        Converter<ResponseBody, Object> delegate =
                retrofit.responseBodyConverter(innerType, annotations);
        return new OptionalConverter<>(delegate);
    }
}
复制代码

很明显只能转化为Optional,并且如果是Optional还会再检查其持有类型,至此通过requestFactory(解析注解获取)、CallAdapter(根据方法返回值寻找)、Convert(根据将ResponseBody转化为指定类型寻找)、Call.Factory(默认设置是新建的OkHttpClient实例,可以传入自己的Call.Factory)构建出HttpServiceMethod实例,然后将其放入 serviceMethodCache 中,到此 eagerlyValidateMethods 分析完毕,接着回到retrofit.create方法

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
        eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},
            new InvocationHandler() {
                private final Platform platform = Platform.get();
                private final Object[] emptyArgs = new Object[0];
                @Override
                public Object invoke(Object proxy, Method method, @Nullable Object[] args)
                        throws Throwable {
                    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);
                }
            });
}
复制代码

这里就是一个动态代理,当调用create方法返回的实例的任何方法都会直接回调invoke方法。

四、api.inTheater方法的调用

上述动态代理内部判断如果调用的方法来自Object那么直接调用,如果调用的是默认方法在Android中会直接抛出错误,此外就去获取ServiceMethod实例调用其invoke方法,由于我们刚才已经把所有ServiceMethod都放入到了serviceMethodCache中因此直接取出执行就行了。接着看HttpServiceMethod的invoke方法

// HttpServiceMethod.java
@Override ReturnT invoke(Object[] args) {
return callAdapter.adapt(
    new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
复制代码

如果按照本文刚开始的例子那么callAdapter由DefaultCallAdapterFactory.get获取

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

相对于直接返回给外界了一个OkHttpCall实例,继续看看该类的execute方法

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());
}
复制代码

这个OkHttpCall与RealCall一致都只能被执行一次,先不去管响应,接着调用createRawCall创建RealCall实例

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;
}
复制代码

这里的callFactoty一般也就是一个OkHttpClient实例,来看看requestFactory.create是如何创建一个Request实例

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 requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
            headers, contentType, hasBody, isFormEncoded, isMultipart);
    List<Object> argumentList = new ArrayList<>(argumentCount);
    // 调用每个ParameterHandler实例的apply方法
    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();
}
复制代码

inTheaters方法有一个参数,根据上述源码我们知道其会创建一个ParameterHandler.Query实例,看看其apply方法

// 这里的valueConverter其实是遍历了converterFactories然后调用stringConverter,如果我们没设置那么默认
// valueConverter就是BuiltInConverters里面的ToStringConverter实例
static final class Query<T> extends ParameterHandler<T> {
    private final String name;
    private final Converter<T, String> valueConverter;
    private final boolean encoded;
    Query(String name, Converter<T, String> valueConverter, boolean encoded) {
        this.name = checkNotNull(name, "name == null");
        this.valueConverter = valueConverter;
        this.encoded = encoded;
    }
    @Override
    void apply(RequestBuilder builder, @Nullable T value) throws IOException {
        if (value == null) return; // Skip null values.
        String queryValue = valueConverter.convert(value);
        if (queryValue == null) return; // Skip converted but null values
        builder.addQueryParam(name, queryValue, encoded);
    }
}
static final class ToStringConverter implements Converter<Object, String> {
    static final ToStringConverter INSTANCE = new ToStringConverter();
    @Override
    public String convert(Object value) {
        return value.toString();
    }
}
复制代码

很明显ParameterHandler.Query只是添加了一个请求参数,接着调用requestBuilder.get去真正的创建 okhttp3.Request.Builder实例

Request.Builder get() {
    HttpUrl url;
    HttpUrl.Builder urlBuilder = this.urlBuilder;
    if (urlBuilder != null) {
        url = urlBuilder.build();
    } else {
        // 组合Url
        url = baseUrl.resolve(relativeUrl);
        if (url == null) {
            throw new IllegalArgumentException(
                    "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
        }
    }
    RequestBody body = this.body;
    if (body == null) {
        if (formBuilder != null) {
            body = formBuilder.build();
        } else if (multipartBuilder != null) {
            body = multipartBuilder.build();
        } else if (hasBody) {
            body = RequestBody.create(null, new byte[0]);
        }
    }
    MediaType contentType = this.contentType;
    if (contentType != null) {
        if (body != null) {
            body = new ContentTypeOverridingRequestBody(body, contentType);
        } else {
            requestBuilder.addHeader("Content-Type", contentType.toString());
        }
    }
    return requestBuilder
            .url(url)
            .method(method, body);
}
复制代码

至此创建Request实例成功,接着调用了call.execute方法执行网络请求,接下来看看其是如何解析响应的

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
        ResponseBody rawBody = rawResponse.body();
    // 首先移除了响应体,以便于长时间保存Response
    rawResponse = rawResponse.newBuilder()
            .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();
    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
        try {
            // 将响应体全部读入内存,封装成一个错误的响应
            ResponseBody bufferedBody = Utils.buffer(rawBody);
            return Response.error(bufferedBody, rawResponse);
        } finally {
            rawBody.close();
        }
    }
    if (code == 204 || code == 205) {
        rawBody.close();
        // 204、205无响应体封装成一个成功的响应
        return Response.success(null, rawResponse);
    }
    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
        T body = responseConverter.convert(catchingBody);
        return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
        catchingBody.throwIfCaught();
        throw e;
    }
}
复制代码

最终调用responseConverter的convert方法将ResponseBody实例转化为指定的类型,由于本例中inTheaters方法返回值为Call<ResponseBody>,因此这里的T就是ResponseBody类型,而responseConverter就是BufferingResponseBodyConverter实例

static final class BufferingResponseBodyConverter
            implements Converter<ResponseBody, ResponseBody> {
    static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
    @Override
    public ResponseBody convert(ResponseBody value) throws IOException {
        try {
            return Utils.buffer(value);
        } finally {
            value.close();
        }
    }
}
复制代码

内部直接将所有ResponseBody全部读入内存,然后新建一个Response实例返回,parseResponse最后再调用Response.success构造一个成功的响应返回给外界,至此Retrofit的基本工作流程已经梳理完毕。下面来看看CallAdapter和Convert的作用

五、CallAdapter、Converter的作用

首先看看CallAdapter,下面是它的接口定义

public interface CallAdapter<R, T> {

    // 返回一个代理了call的实例,不需要代理就原样返回好了
    T adapt(Call<R> call);
    
    // 返回T所对应的类型,{@code Call<Repo>} is {@code Repo}
    Type responseType();
    
    abstract class Factory {
        // 返回一个能处理接口返回类型的CallAdapter,如果不能处理该类型就返回null
        public abstract @Nullable
        CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
                              Retrofit retrofit);
                              
        // 提取指定index位置泛型参数类型的上界
        // index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
        protected static Type getParameterUpperBound(int index, ParameterizedType type) {
            return Utils.getParameterUpperBound(index, type);
        }
        // 获取原始的类型 {@code List<? extends Runnable>} returns {@code List.class}.
        protected static Class<?> getRawType(Type type) {
            return Utils.getRawType(type);
        }
    }
}
复制代码

在创建HttpServiceMethod的时候会遍历所有的CallAdapter.Factory并调用其get方法,一旦某个CallAdapter.Factory的get方法不返回null就停止遍历,如果所有的都返回null,那么会报错。如果成功返回CallAdapter实例callAdapter,那么接着调用callAdapter的responseType方法获取到泛型类型,接着根据这个泛型类型去ConvertFactory列表中寻找可以将ResponseBody转化为该泛型类型的Converter。最后在内部创建OkHttpCall后会调用adapt方法。总结下就是在get方法中判断returnType是否能处理,如果能处理的话,adapt方法必须要将call转化为returnbType类型的实例,接着看看Converter,下面是它的定义

public interface Converter<F, T> {
    @Nullable
    T convert(F value) throws IOException;
    abstract class Factory {
        // 返回一个能将ResponseBody转化为type类型的Converter,如果不能转换那么返回null
        public @Nullable
        Converter<ResponseBody, ?> responseBodyConverter(Type type,
            Annotation[] annotations, Retrofit retrofit) {
            return null;
        }
        // 返回一个能将type类型转换为RequestBody类型的Converter,如果不能转换那么返回null
        // 只在拥有@Body或者@Part或者@PartMap时才会调用
        public @Nullable
        Converter<?, RequestBody> requestBodyConverter(Type type,
            Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
            return null;
        }
        // 返回一个能将制定类型转换为字符串的Converter,只在拥有以下注解时才会调用
        // @Field、@FieldMap、@Header、@HeaderMap、@Path、@Query、@QueryMap
        Converter<?, String> stringConverter(Type type, Annotation[] annotations,
                                             Retrofit retrofit) {
            return null;
        }
        // 这两个方法与CallAdapterFactory一致
        protected static Type getParameterUpperBound(int index, ParameterizedType type) {
            return Utils.getParameterUpperBound(index, type);
        }
        protected static Class<?> getRawType(Type type) {
            return Utils.getRawType(type);
        }
    }
}
复制代码

Converter.Factory提供了responseBodyConverter、requestBodyConverter、stringConverter三个重要方法,分别用于将ResponseBody转换为指定类型、将指定类型转换为RequestBody、将指定类型转换为String。三个方法都返回值都是一个Converter实例其只有一个方法convert方法内部做转换操作,下面为了加深理解我们来看看GsonConverterFactory的源码

public final class GsonConverterFactory extends Converter.Factory {
    public static GsonConverterFactory create() {
        return create(new Gson());
    }
    public static GsonConverterFactory create(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        return new GsonConverterFactory(gson);
    }
    private final Gson gson;
    private GsonConverterFactory(Gson gson) {
        this.gson = gson;
    }
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new GsonResponseBodyConverter<>(gson, adapter);
    }
    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new GsonRequestBodyConverter<>(gson, adapter);
    }
}

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
    private final Gson gson;
    private final TypeAdapter<T> adapter;

    GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }
    @Override
    public T convert(ResponseBody value) throws IOException {
        // 获取输入流转换成JsonReader实例,然后调用read转换为指定类型的实例
        JsonReader jsonReader = gson.newJsonReader(value.charStream());
        try {
            T result = adapter.read(jsonReader);
            if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
                throw new JsonIOException("JSON document was not fully consumed.");
            }
            return result;
        } finally {
            value.close();
        }
    }
}
final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
    private static final Charset UTF_8 = Charset.forName("UTF-8");

    private final Gson gson;
    private final TypeAdapter<T> adapter;

    GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }

    @Override
    public RequestBody convert(T value) throws IOException {
        // 获取输出流构建成JsonWrite实例,然后调用write方法写入buffer中
        Buffer buffer = new Buffer();
        Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
        JsonWriter jsonWriter = gson.newJsonWriter(writer);
        adapter.write(jsonWriter, value);
        jsonWriter.close();
        return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
    }
}
复制代码

六、总结

Retrofit的工作流程主要包括解析注解、动态代理、Request的生成、Response的解析四个大步骤,内部默认还是使用了OkHttp进行网络请求,其中前两步顺序可能会相反这取决于validateEagerly是否为true,Request的生成和Response的解析依赖于CallAdapterFactory和ConverterFactory。


以上所述就是小编给大家介绍的《Retrofit源码分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Flask Web开发实战

Flask Web开发实战

李辉 / 机械工业出版社 / 2018-8-1 / 129

这是一本面向Python程序员的,全面介绍Python Web框架Flask的书。关于本书的详细介绍、相关资源等更多信息可以访问本书的官方主页http://helloflask.com/book了解。 • 国内首本Flask著作,在内容上涵盖完整的Flask Web开发学习路径,在实践上包含完整的Flask Web程序开发流程。同时兼容Python2 .7和Python3.6。 • 内......一起来看看 《Flask Web开发实战》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具