阅读 338

Android 网络编程:Retrofit源码解析

版权声明:本文为博主原创文章,未经博主允许不得转载
文章分类:Android知识体系 - 网络编程
复制代码

一、前言

Retrofit是一个基于OkHttp、遵循RESTful API设计风格的网络请求封装框架,本文将按照其工作流程逐步分析对应的源码(本文使用的Retrofit版本为2.5.0)


二、源码分析

1. 请求示例

以下是一次简单的请求示例,首先我们需要定义一个接口API,并使用注解描述其中的API方法

public interface ExpressService {
    @GET("query")
    Call<ResponseBody> get(@Query("type") String type, @Query("postid") String postid);
}
复制代码

然后是Retrofit的工作流,可以分为三步:

  1. 构建Retrofit对象
  2. 加载API方法配置,生成请求执行器Call
  3. 使用Call对象执行请求,处理响应数据
public void asyncGet() {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://www.kuaidi100.com/")
            .build();

    ExpressService expressService = retrofit.create(ExpressService.class);
    Call<ResponseBody> call = expressService.get("ems", "11111111");

    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {

        }
    });
}
复制代码

下面我们将按照上述过程,分析对应的源码

2. 构建Retrofit对象

本章我们将分析Retrofit对象构建的过程,以下是对应的示例代码

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://www.kuaidi100.com/")
        .build();
复制代码

2.1 Retrofit类的成员变量

首先来看Retrofit类声明了哪些成员变量

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

    final okhttp3.Call.Factory callFactory;
    final HttpUrl baseUrl;
    final List<Converter.Factory> converterFactories;
    final List<CallAdapter.Factory> callAdapterFactories;
    final @Nullable Executor callbackExecutor;
    final boolean validateEagerly;

    ...
}
复制代码
  • serviceMethodCache:serviceMethodCache是一个ConcurrentHashMap类型的Map集合,因此它支持并发操作且线程安全,其存储对象是ServiceMethod。ServiceMethod我们可以理解是API方法的配置器以及代理中转站,具体内容会在后文进行分析

  • callFactory:callFactory就是生产请求执行器的工厂(Call.Factory),Retrofit中默认的请求执行器工厂是OkHttpClient。如果我们没有设置自定义的请求执行器工厂,那么就会在构建Retrofit对象的过程中为我们创建一个OkHttpClient实例

  • baseUrl:API接口基地址的封装对象,类型为HttpUrl

  • converterFactories数据转换器工厂(Converter.Factory)的集合,该工厂的产品数据转换器(Converter)作用是对请求与响应数据进行序列化和反序列化

  • callAdapterFactories请求适配器工厂(CallAdapter.Factory)的集合,该工厂的产品请求适配器(CallAdapter)用于改变执行请求的方式,例如我们可以通过添加支持RxJava的请求适配器,将默认执行请求的方式改为RxJava调用链的方式

  • callbackExecutor回调执行器,主要作用是处理请求回调,例如将回调所在线程从子线程切换至主线程

  • validateEagerly是否提前加载API方法配置的标志位

2.2 构建Builder

Retrofit对象通过建造者模式进行构建,我们来看下Builder是如何初始化的

public static final class Builder {
    private final Platform platform;
    ...

    Builder(Platform platform) {
        this.platform = platform;
    }

    public Builder() {
        this(Platform.get());
    }
    ...
}
复制代码

我们看见Builder的构造方法需要传入Platform对象,它的主要作用是根据运行平台为Retrofit提供默认的配置方法、工厂类或者工厂类的集合。Platform可以通过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) {
        }
        try {
            Class.forName("java.util.Optional");
            return new Java8();
        } catch (ClassNotFoundException ignored) {
        }
        return new Platform();
    }
    ...
}
复制代码

调用Platform.get()方法获取的是静态成员变量PLATFORM,PLATFORM则通过findPlatform()方法生成

findPlatform()主要通过是否能查找到指定的类来判断当前Retrofit运行的平台,如果是运行在Android平台,则返回Platform.Android的实例;如果是Java平台,则返回Platform.Java8的实例;如果两者皆非,则返回Platform自身的实例

现在我们是在Android平台下运行Retrofit,所以继续往下看Platform.Android的代码

// Platform
static class Android extends Platform {
    @IgnoreJRERequirement // Guarded by API check.
    @Override
    boolean isDefaultMethod(Method method) {
        if (Build.VERSION.SDK_INT < 24) {
            return false;
        }
        return method.isDefault();
    }

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

    @Override
    List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
            @Nullable Executor callbackExecutor) {
        if (callbackExecutor == null) throw new AssertionError();
        ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
        return Build.VERSION.SDK_INT >= 24
                ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
                : singletonList(executorFactory);
    }

    @Override
    int defaultCallAdapterFactoriesSize() {
        return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
    }

    @Override
    List<? extends Converter.Factory> defaultConverterFactories() {
        return Build.VERSION.SDK_INT >= 24
                ? singletonList(OptionalConverterFactory.INSTANCE)
                : Collections.<Converter.Factory>emptyList();
    }

    @Override
    int defaultConverterFactoriesSize() {
        return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
    }

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

        @Override
        public void execute(Runnable r) {
            handler.post(r);
        }
    }
}
复制代码

Platform.Android中主要定义了以下内容:

  • 默认的回调执行器MainThreadExecutor,负责将请求回调的运行线程切换为主线程
  • 默认的请求适配器工厂集合,当Android版本大于等于24时,集合依次添加了两个适配器工厂CompletableFutureCallAdapterFactoryExecutorCallAdapterFactory;当Android版本小于24时,则为只存储了ExecutorCallAdapterFactory的单元素集合
  • 默认的数据转换器工厂集合,当Android版本大于等于24时,返回的是只储存了OptionalConverterFactory的单元素集合;当系统版本小于24时,返回的是一个空集合

以上平台默认的内容都会在Builder调用build()完成构建时用到,具体的我们待会再细说,现在先来看下Builder主要提供了哪些方法

// Retrofit.Builder
public Builder client(OkHttpClient client) {
    return callFactory(checkNotNull(client, "client == null"));
}

public Builder callFactory(okhttp3.Call.Factory factory) {
    this.callFactory = checkNotNull(factory, "factory == null");
    return this;
}

public Builder baseUrl(String baseUrl) {
    checkNotNull(baseUrl, "baseUrl == null");
    return baseUrl(HttpUrl.get(baseUrl));
}

public Builder addConverterFactory(Converter.Factory factory) {
    converterFactories.add(checkNotNull(factory, "factory == null"));
    return this;
}

public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
    callAdapterFactories.add(checkNotNull(factory, "factory == null"));
    return this;
}

public Builder callbackExecutor(Executor executor) {
    this.callbackExecutor = checkNotNull(executor, "executor == null");
    return this;
}

public Builder validateEagerly(boolean validateEagerly) {
    this.validateEagerly = validateEagerly;
    return this;
}
复制代码

简单介绍一下这些方法的作用

  • client():添加自定义配置的OkHttpClient
  • callFactory():添加自定义的请求执行器工厂
  • baseUrl():添加API接口的基地址
  • addConverterFactory():添加自定义的数据转换器
  • addCallAdapterFactory():添加自定义的请求适配器
  • callbackExecutor():添加自定义的回调执行器
  • validateEagerly():设置是否预加载API方法的标志位

完成Retrofit的构建最终需要调用Builder.build()方法,来看下源码

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

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

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

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

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

    // Add the built-in converter factory first. This prevents overriding its behavior but also
    // ensures correct behavior when using converters that consume all types.
    converterFactories.add(new BuiltInConverters());
    converterFactories.addAll(this.converterFactories);
    converterFactories.addAll(platform.defaultConverterFactories());

    return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
            unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
复制代码

build()方法完成了以下工作:

  • 当用户没有添加自定义的CallFactory时默认使用OkHttpClient
  • 当用户没有添加自定义的CallbackExecutor时默认使用Platform.defaultCallbackExecutor(),即MainThreadExecutor
  • callAdapterFactories创建一个保护性拷贝,然后将Platform里定义的所有请求适配器添加进来
  • converterFactories创建了一个保护性拷贝,然后依次将内置的转换器工厂BuiltInConverters、所有自定义的转换器工厂、Platform里定义的所有转换器工厂添加进来

完成上述工作后将相关参数传入Retrofit的构造方法中即完成构建Retrofit对象的工作。其中需要注意的是converterFactories和callAdapterFactories都变成了不可修改的List集合,这意味着后续我们不可以再更改这两个集合中的内容了

至此Retrofit对象构建的过程就分析完了,下一章我们将分析API接口方法加载配置以及转换为请求执行器的过程

2.3 本章小结

这一章我们分析了构建Retrofit对象的过程,过程中主要完成了以下工作:

  • 创建内置的成员实例以及工厂集合,用来维持基础的功能
  • 通过构建方法保存用户自定义的内容,例如自定义的数据转换器、请求适配器、回调执行器等等,用来运行扩展的功能

3. 加载API方法配置

本章我们将分析API方法加载配置的过程,以下是对应的示例代码

// 请求示例
ExpressService expressService = retrofit.create(ExpressService.class);
Call<ResponseBody> call = expressService.get("ems", "11111111");
复制代码

Retrofit对象构建完毕后,下一步是通过Retrofit.create(Class<T> service)方法实现API接口,该方法的代码如下

// Retrofit
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 @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);
                }
            });
}
复制代码

该方法主要是通过运用动态代理的方式为请求接口生成一个代理对象,我们对接口所有方法的调用都会转发到代理对象中。现在我们一步步分析是如何完成整个动态代理的过程的

3.1 API方法的校验和预加载

首先是调用Utils.validateServiceInterface(Class<T> service)对接口类进行校验

// Utils
static <T> void validateServiceInterface(Class<T> service) {
    if (!service.isInterface()) {
        throw new IllegalArgumentException("API declarations must be interfaces.");
    }
    // Prevent API interfaces from extending other interfaces. This not only avoids a bug in
    // Android (http://b.android.com/58753) but it forces composition of API declarations which is
    // the recommended pattern.
    if (service.getInterfaces().length > 0) {
        throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
    }
}
复制代码

这里规定我们传入的参数必须是一个接口类,并且该接口不能继承其他的接口

回到create方法中,接下来会通过标志位validateEagerly来决定是否提前为API方法加载相应的配置

// Retrofit.create
if (validateEagerly) {
    eagerlyValidateMethods(service);
}
复制代码

我们知道动态代理是在接口方法被调用时才会生效的,这类似于懒加载策略,Retrofit默认采用的就是这种方式,而我们可以通过Retrofit.Builder.validateEagerly()方法将validateEagerly标志设置为true,Retrofit就会调用eagerlyValidateMethods()提前为接口方法加载配置

eagerlyValidateMethods()源码如下

// Retrofit
private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
            loadServiceMethod(method);
        }
    }
}
复制代码

具体逻辑为遍历接口中的方法(method),然后判断方法是否为默认方法静态方法(接口的默认方法和静态方法都是Java8新增的特性),若不是则调用loadServiceMethod()为接口方法加载相应的配置。loadServiceMethod()方法的逻辑我们待会再细说,现在继续分析Retrofit.create()方法

经过预加载的逻辑后,下一步就是执行动态代理相关的逻辑

3.2 动态代理中的校验

// Retrofit.create
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);
            }
        });
复制代码

首先依然是对接口方法的校验,会判断此次调用的方法是否为Object对象的方法(非接口方法),若是则正常调用,不进行任何代理操作。然后判断该方法是否为默认方法,若是则调用Platform对象提供的配置方法invokeDefaultMethod()并返回。invokeDefaultMethod()在Android平台下会抛出UnsupportedOperationException异常,具体代码如下

// Platform
@Nullable
Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object,
                           @Nullable Object... args) throws Throwable {
    throw new UnsupportedOperationException();
}
复制代码

执行完所有的校验工序之后,最终依然是调用loadServiceMethod()开始加载API方法的配置,我们来看下源码

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

方法的逻辑非常简单,功能可以分为两部分来看

  • 使用retrofit2.ServiceMethod处理接口方法
  • 将处理后的结果缓存至serviceMethodCache中,这样下次再调用该接口方法时就无需重复处理了

继续往下看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是一个抽象类,它只有两个方法,一个是invoke(),这是一个抽象方法,具体的逻辑由ServiceMethod的子类实现,当调用接口方法时会被动态代理到这个方法中

另一个方法是parseAnnotations(),这是一个静态方法,它的功能如下

  • 创建RequestFactory实例,具体方式为调用RequestFactory.parseAnnotations()方法
  • 校验接口方法的返回类型。Retrofit会判断该返回类型是否属于无法处理的类型(包含类型变量、通配符的返回类型以及void类型),若接收到这些返回类型时会直接抛出异常
  • 继续调用HttpServiceMethod.parseAnnotations()完成接口方法后续的配置加载工作

这一部分最主要的关注点是RequestFactory。RequestFactory是请求体对象(okhttp3.Request)的工厂类,我们可以调用RequestFactory.create()创建一个请求体的实例,下面我们就来详细分析生成RequestFactory的过程

3.3 生成RequestFactory

以下是与RequestFactory.parseAnnotations()方法相关的代码

final class RequestFactory {
    static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
        return new Builder(retrofit, method).build();
    }
    ...
    RequestFactory(Builder builder) {
        method = builder.method;
        baseUrl = builder.retrofit.baseUrl;
        httpMethod = builder.httpMethod;
        relativeUrl = builder.relativeUrl;
        headers = builder.headers;
        contentType = builder.contentType;
        hasBody = builder.hasBody;
        isFormEncoded = builder.isFormEncoded;
        isMultipart = builder.isMultipart;
        parameterHandlers = builder.parameterHandlers;
        isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
    }
    ...
    static final class Builder {
        ...
        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.).");
            }

            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, lastParameter = parameterCount - 1; p < parameterCount; p++) {
                parameterHandlers[p] =
                        parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
            }

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

        ...
    }
}
复制代码

RequestFactory同样通过建造者模式来构建实例,我们可以看到Builder.build()方法中有许多状态位的校验逻辑,主要作用是当用户在创建请求接口中错误地使用注解或配置参数时,可以抛出相应的异常告知用户。这部分的细节就不一一查看了,感兴趣的同学可以自行研究

这里我们最主要关注的地方有两点:一是遍历接口方法的注解,然后通过Builder.parseMethodAnnotation()方法解析注解的过程;二是遍历方法的参数,然后通过Builder.parseParameter()方法解析参数的过程

3.3.1 解析方法注解

首先来看第一点,parseMethodAnnotation()的代码如下

// RequestFactory.Builder
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方法的,例如@DELETE@GET@POST等,解析方法为parseHttpMethodAndPath(),来看下源码

// RequestFactory.Builder
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);
}
复制代码

这个方法有三个参数

  • httpMethod:表示描述HTTP方法的注解的名称
  • value:注解包含的内容,例如@GET("query?type=ems&postid=11111111")中括号里的内容实际上就是指服务端接口Url的资源路径和查询参数部分。这些内容可以通过调用这一系列注解的value()方法获取,这是在定义注解时设置的
  • hasBody:该HTTP方法是否携带请求正文数据

知道了每个参数的含义,后面的代码就好理解了,流程是这样的:首先会对一个接口方法是否同时设置了多个HTTP方法注解进行了校验;然后校验value是否为空,为空就不需要继续解析了,因为这部分内容不是在方法注解里设置就是在方法参数中设置,这里没有,那就直接交给后面解析参数时再去处理;若value不为空,则校验查询参数部分是否符合要求,符合要求则继续解析查询参数字符串得到参数集合,不符合则抛出异常,这些操作主要通过Java正则解析相关的Matcher类完成的,就不细说了

回到RequestFactory.Builder.parseMethodAnnotation(),我们来看第二类注解。第二类注解只有@Headers一个,负责设置请求头信息,解析的方法为Builder.parseHeaders(),这部分内容比较简单,就不展开了

第三类注解主要负责描述请求报文数据的类型,有@Multipart@FormUrlEncoded两种,但因为这两种类型都需要配合方法参数的注解使用,所以这里的处理过程只是简单地校验两者不重复设置就行

实际上方法注解中还有第四类,那就是@Streaming,这是用于描述响应正文数据的,因此Retrofit将它的处理过程放到了后面配置响应内容相关的部分再进行

至此解析方法注解的部分我们就分析完了,接下来看解析参数的部分

3.3.2 解析方法参数

解析方法参数对应的方法是Builder.parseParameter(),代码如下

// RequestFactory.Builder
private @Nullable ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
    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;
        }
    }
    ...
    return result;
}
复制代码

这里的核心逻辑是通过parseParameterAnnotation()方法解析参数注解生成ParameterHandler对象,同时规定一个参数只能设置一个Retrofit定义的注解

ParameterHandler是一个抽象类,它的子类封装了参数的数据和数据的处理过程,并且和不同注解类型的参数一一对应,例如子类ParameterHandler.Query封装了@Query注解的参数,ParameterHandler.Field则封装了@Field注解的参数

作为参数的处理器,ParameterHandler可以在构建请求体对象时利用专属的参数数据转换器将数据转换成请求需要的格式,这里我们以ParameterHandler.Query为例进行分析

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

ParameterHandler.Query有三个成员属性,其中name和encoded对应了@Query定义的属性

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Query {
  /** The query parameter name. */
  String value();

  /**
   * Specifies whether the parameter {@linkplain #value() name} and value are already URL encoded.
   */
  boolean encoded() default false;
}
复制代码

而valueConverter指的就是参数数据转换器,它可以通过调用convert()方法进行数据转换。参数处理的过程都放在Query.apply()方法中,当构建请求体需要此参数的数据时,就会调用apply()方法,然后通过传入的RequestBuilder引用设置数据

ParameterHandler的分析就到这,其他参数处理器就不一一分析了,因为套路基本上都是一样的,现在我们继续分析parseParameterAnnotation()方法是如何生成ParameterHandler的

// RequestFactory.Builder
@Nullable
private ParameterHandler<?> parseParameterAnnotation(
        int p, Type type, Annotation[] annotations, Annotation annotation) {
    if (annotation instanceof Url) {
        ...
        return new ParameterHandler.RelativeUrl(method, p);
    } else if (annotation instanceof Path) {
        ...
        Converter<?, String> converter = retrofit.stringConverter(type, annotations);
        return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());
    } else if (annotation instanceof Query) {
        ...
        if (Iterable.class.isAssignableFrom(rawParameterType)) {
            ...
            Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
            return new ParameterHandler.Query<>(name, converter, encoded).iterable();
        } else if (rawParameterType.isArray()) {
            ...
            Converter<?, String> converter = retrofit.stringConverter(arrayComponentType, annotations);
            return new ParameterHandler.Query<>(name, converter, encoded).array();
        } else {
            Converter<?, String> converter = retrofit.stringConverter(type, annotations);
            return new ParameterHandler.Query<>(name, converter, encoded);
        }
    } else if (annotation instanceof QueryName) {
        ...
        if (Iterable.class.isAssignableFrom(rawParameterType)) {
            ...
            Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
            return new ParameterHandler.QueryName<>(converter, encoded).iterable();
        } else if (rawParameterType.isArray()) {
            ...
            Converter<?, String> converter = retrofit.stringConverter(arrayComponentType, annotations);
            return new ParameterHandler.QueryName<>(converter, encoded).array();
        } else {
            Converter<?, String> converter = retrofit.stringConverter(type, annotations);
            return new ParameterHandler.QueryName<>(converter, encoded);
        }
    } else if (annotation instanceof QueryMap) {
        ...
        Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
        return new ParameterHandler.QueryMap<>(method, p,
                valueConverter, ((QueryMap) annotation).encoded());
    } else if (annotation instanceof Header) {
        ...
        if (Iterable.class.isAssignableFrom(rawParameterType)) {
            ...
            Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
            return new ParameterHandler.Header<>(name, converter).iterable();
        } else if (rawParameterType.isArray()) {
            ...
            Converter<?, String> converter = retrofit.stringConverter(arrayComponentType, annotations);
            return new ParameterHandler.Header<>(name, converter).array();
        } else {
            Converter<?, String> converter = retrofit.stringConverter(type, annotations);
            return new ParameterHandler.Header<>(name, converter);
        }
    } else if (annotation instanceof HeaderMap) {
        ...
        Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
        return new ParameterHandler.HeaderMap<>(method, p, valueConverter);
    } else if (annotation instanceof Field) {
        ...
        if (Iterable.class.isAssignableFrom(rawParameterType)) {
            ...
            Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
            return new ParameterHandler.Field<>(name, converter, encoded).iterable();
        } else if (rawParameterType.isArray()) {
            ...
            Converter<?, String> converter = retrofit.stringConverter(arrayComponentType, annotations);
            return new ParameterHandler.Field<>(name, converter, encoded).array();
        } else {
            Converter<?, String> converter = retrofit.stringConverter(type, annotations);
            return new ParameterHandler.Field<>(name, converter, encoded);
        }
    } else if (annotation instanceof FieldMap) {
        ...
        Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
        return new ParameterHandler.FieldMap<>(method, p, valueConverter, ((FieldMap) annotation).encoded());
    } else if (annotation instanceof Part) {
        ...
        String partName = part.value();
        if (partName.isEmpty()) {
            if (Iterable.class.isAssignableFrom(rawParameterType)) {
                ...
                return ParameterHandler.RawPart.INSTANCE.iterable();
            } else if (rawParameterType.isArray()) {
                ...
                return ParameterHandler.RawPart.INSTANCE.array();
            } else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
                return ParameterHandler.RawPart.INSTANCE;
            } else {
                ...
            }
        } else {
            Headers headers =
                    Headers.of("Content-Disposition", "form-data; name=\"" + partName + "\"",
                            "Content-Transfer-Encoding", part.encoding());

            if (Iterable.class.isAssignableFrom(rawParameterType)) {
                ...
                Converter<?, RequestBody> converter =
                        retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations);
                return new ParameterHandler.Part<>(method, p, headers, converter).iterable();
            } else if (rawParameterType.isArray()) {
                ...
                Converter<?, RequestBody> converter =
                        retrofit.requestBodyConverter(arrayComponentType, annotations, methodAnnotations);
                return new ParameterHandler.Part<>(method, p, headers, converter).array();
            } else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
                ...
            } else {
                Converter<?, RequestBody> converter =
                        retrofit.requestBodyConverter(type, annotations, methodAnnotations);
                return new ParameterHandler.Part<>(method, p, headers, converter);
            }
        }
    } else if (annotation instanceof PartMap) {
        ...
        Converter<?, RequestBody> valueConverter =
                retrofit.requestBodyConverter(valueType, annotations, methodAnnotations);
        return new ParameterHandler.PartMap<>(method, p, valueConverter, partMap.encoding());
    } else if (annotation instanceof Body) {
        ...
        Converter<?, RequestBody> converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations);
        return new ParameterHandler.Body<>(method, p, converter);
    } else if (annotation instanceof Tag) {
        ...
        return new ParameterHandler.Tag<>(tagType);
    }
    return null; // Not a Retrofit annotation.
}
复制代码

由于方法注解很多,parseParameterAnnotation()代码非常的多,因此这里我只把核心的内容展示给大家。parseParameterAnnotation()解析每个参数的过程大致可以总结为三步

  • 校验参数是否设置正确,错误则抛出异常告知用户
  • 生成特定的参数数据转换器
  • 返回对应的ParameterHandler实例

校验过程就不细说了,感兴趣的同学可以自行查阅源码,我们重点关注参数数据转换器是如何生成的。从上面的源码可以看出生成转换器的方式主要有两种,一种是通过Retrofit.stringConverter()方法生成,这类转换器转换出来的数据类型为String;另一种则通过Retrofit.requestBodyConverter()方法生成,对应的转换结果就是请求实体类型RequestBody

先来看Retrofit.stringConverter()

// Retrofit
public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");

    for (int i = 0, count = converterFactories.size(); i < count; i++) {
        Converter<?, String> converter =
                converterFactories.get(i).stringConverter(type, annotations, this);
        if (converter != null) {
            //noinspection unchecked
            return (Converter<T, String>) converter;
        }
    }

    // Nothing matched. Resort to default converter which just calls toString().
    //noinspection unchecked
    return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;
}
复制代码

这里的代码主要完成了以下工作:按顺序遍历数据转换器工厂集合converterFactories,到符合要求的转换器工厂,即在实现接口方法Converter.Factory.stringConverter()时不能返回null。这里有一点细节需要注意,在遍历过程中只要发现符合的转换器工厂就会返回,因此转换器工厂添加的顺序决定了它们的优先级越早添加的优先级越高,就可以优先被征调。还记得我们在构建Retrofit对象时添加的转换器吗?现在我们重新来回顾一下加深记忆

// Retrofit.Builder.build()
converterFactories.add(new BuiltInConverters());// 添加Retrofit内置的数据转换器,优先级最高
converterFactories.addAll(this.converterFactories);// 按顺序添加所有自定义的数据转换器
converterFactories.addAll(platform.defaultConverterFactories());// 添加针对对应运行平台设置的数据转换器工厂
复制代码

当内置转换器工厂BuiltInConverters以及集合中其他转换器工厂都不符合要求时,则返回特定的转换器BuiltInConverters.ToStringConverter,其代码如下

// BuiltInConverters
static final class ToStringConverter implements Converter<Object, String> {
    static final ToStringConverter INSTANCE = new ToStringConverter();

    @Override
    public String convert(Object value) {
        return value.toString();
    }
}
复制代码

代码很简单就不细说了,接下来是Retrofit.requestBodyConverter()

public <T> Converter<T, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {
    return nextRequestBodyConverter(null, type, parameterAnnotations, methodAnnotations);
}

public <T> Converter<T, RequestBody> nextRequestBodyConverter(
        @Nullable Converter.Factory skipPast, Type type, Annotation[] parameterAnnotations,
        Annotation[] methodAnnotations) {
    checkNotNull(type, "type == null");
    checkNotNull(parameterAnnotations, "parameterAnnotations == null");
    checkNotNull(methodAnnotations, "methodAnnotations == null");

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
        Converter.Factory factory = converterFactories.get(i);
        Converter<?, RequestBody> converter =
                factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this);
        if (converter != null) {
            //noinspection unchecked
            return (Converter<T, RequestBody>) converter;
        }
    }

    // 没有找到符合要求的请求数据转换器,抛出IllegalArgumentException异常
    ...
}
复制代码

和之前的处理逻辑差别不大,不过这次调用的方法为Converter.Factory.requestBodyConverter(),而且我们发现BuiltInConverters实现了该接口方法,代码如下

// BuiltInConverters
@Override
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
                                               Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
        return RequestBodyConverter.INSTANCE;
    }
    return null;
}
复制代码

这里返回了针对RequestBody类型参数的转换器BuiltInConverters.RequestBodyConverter

// BuiltInConverters
static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
    static final RequestBodyConverter INSTANCE = new RequestBodyConverter();

    @Override
    public RequestBody convert(RequestBody value) {
        return value;
    }
}
复制代码

可以看见RequestBodyConverter并没有对参数数据进行任何处理,因此该转换器最主要的作用是拦截类型为RequestBody的参数

至此我们就完了解析方法参数的全部工作,也成功生成了请求体对象工厂RequestFactory

3.4 生成CallAdapter

HttpServiceMethod是ServiceMethod的子类,它的代码有点多,我们直接挑重点看。首先是parseAnnotations()方法

// HttpServiceMethod
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
        Retrofit retrofit, Method method, RequestFactory requestFactory) {
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
    Type responseType = callAdapter.responseType();

    ...

    Converter<ResponseBody, ResponseT> responseConverter =
            createResponseConverter(retrofit, method, responseType);

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

这里主要做了下面这些工作

  • 通过createCallAdapter()方法生成请求适配器callAdapter
  • 通过callAdapter.responseType()方法获取响应数据的类型responseType
  • 通过createResponseConverter()方法生成响应体(Response)的数据转换器responseConverter
  • 通过上述实例构建HttpServiceMethod对象

首先我们分析生成请求适配器CallAdapter的过程,以下是createCallAdapter()方法的代码

// HttpServiceMethod
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
        Retrofit retrofit, Method method) {
    Type returnType = method.getGenericReturnType();
    Annotation[] annotations = method.getAnnotations();
    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
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, 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++) {
        CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
        if (adapter != null) {
            return adapter;
        }
    }

    // 当所有适配器都不符合要求时抛出IllegalArgumentException异常
    ...
}
复制代码

可以发现套路基本上是一样的,具体方式为遍历callAdapterFactories找到符合要求的请求适配器后返回,验证的方法为CallAdapter.Factory.get()。通过上一章的分析我们知道,除了用户添加的自定义的请求适配器工厂以外,Retrofit还内置了两种默认的适配器工厂:CompletableFutureCallAdapterFactory(系统版本大于等于24时生效)和ExecutorCallAdapterFactory。这里我们只以ExecutorCallAdapterFactory为例进行分析,来看下源码

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
    final Executor callbackExecutor;

    ExecutorCallAdapterFactory(Executor callbackExecutor) {
        this.callbackExecutor = callbackExecutor;
    }

    @Override
    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 new ExecutorCallbackCall<>(callbackExecutor, call);
            }
        };
    }
    ...
}
复制代码

通过上述代码我们知道,get()方法指定ExecutorCallAdapterFactory的适配目标是返回类型为retrofit2.Call的API方法,其最终返回值是一个新的CallAdapter实例。此外,该CallAdapter实例的adapt()方法生成了retrofit2.Call的子类ExecutorCallbackCall,这实际上是请求执行器的装饰器,具体内容我们在后面用到时再细说,现在继续下一步

3.5 生成ResponseConverter

接下来是调用HttpServiceMethod.createResponseConverter()方法生成响应数据转换器(ResponseConverter),我们来看下相关代码

// HttpServiceMethod
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
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) {
            //noinspection unchecked
            return (Converter<ResponseBody, T>) converter;
        }
    }

    // 无法找到符合要求的ResponseBodyConverter时抛出IllegalArgumentException异常
    ...
}
复制代码

同样这里也是通过遍历转换器工厂集合converterFactories找到符合要求的转换器工厂,验证方法为Converter.Factory.responseBodyConverter()。之前讲过转换器工厂优先级最高的是内置的BuiltInConverters,来看下它的responseBodyConverter()方法

final class BuiltInConverters extends Converter.Factory {
    ...

    @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;
        }
        ...
        return null;
    }
    ...
}
复制代码

这里指定BuiltInConverters只能处理类型为okhttp3.ResponseBody以及void的响应体数据。当类型为ResponseBody时,还会判断接口方法是否含有@Streaming注解,然后提供不同的转换器实例。下面我们就看下这三个数据转换器有什么区别吧

// BuiltInConverters
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 {
            // Buffer the entire body to avoid future I/O.
            return Utils.buffer(value);
        } finally {
            value.close();
        }
    }
}

static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {
    static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();

    @Override
    public Void convert(ResponseBody value) {
        value.close();
        return null;
    }
}
复制代码

可以看到这三个转换器都实现了Converter接口的convert()方法,这个方法会在后续处理响应数据时调用,现在我们先看下这三个转换器的convert()方法是如何实现的

  • StreamingResponseBodyConverter:会将数据流的连接返回给用户,那为什么返回的是数据流的连接而不是数据呢?原因是RessponseBody持有的数据可能会很大,OkHttp并不会将数据直接保存到内存中,实际保存的是数据流的连接,当用户需要时再通过连接从服务端获取数据。因此@Streaming注解适合在执行大文件下载任务的时候使用
  • BufferingResponseBodyConverter:先将响应体数据保存至内存缓冲区中,再返回给用户。这适合在响应体数据较小的场景下使用,也是默认的数据处理方式
  • VoidResponseBodyConverter:当设置返回的响应体数据类型为void时,说明用户无意处理响应的数据,那么直接关闭释放资源即可

现在回到一开始的请求示例中,我们定义的接口方法是这样的

public interface ExpressService {
    @GET("query?type=ems&postid=11111111")
    Call<ResponseBody> get();
}
复制代码

这里设置的响应数据类型是ResponseBody,即BuiltInConverters可以处理这个API方法,因此遍历查找转换器工厂的过程到了BuiltInConverters处就被拦截了下来,且由于该接口方法并没有添加@Streaming注解,所以最终HttpServiceMethod.createResponseConverter()构建的响应数据转换器就是BufferingResponseBodyConverter

3.6 完成API方法的动态代理

完成所有前置工作后,我们回到Retrofit.create()方法,由之前的分析可知API方法会被动态代理到

loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
复制代码

loadServiceMethod()最终返回的是HttpServiceMethod的实例,因此我们来看下HttpServiceMethod.invoke()方法的代码

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

adapt()方法的传参是OkHttpCall的实例,这是Retrofit层的请求执行器,其内部持有真实的请求执行器okhttp3.Call。OkHttpCall作为代理类主要负责Retrofit层与OkHttp层之间交互数据的转换

此外,从之前的讲解中我们知道adapt()方法的返回结果是ExecutorCallbackCall的实例,因此动态代理API方法最终得到的就是这个实例,其作为OkHttpCall的装饰器,主要负责协同回调执行器为OkHttpCall动态增强回调方面的功能

至此API方法的动态代理和加载配置的过程就分析完了,下一章我们将分析Retrofit是如何发起请求以及处理响应数据的

3.7 本章小结

这一章分析了加载API方法配置的过程,原理是利用动态代理机制,主要完成了以下工作:

  • 通过解析方法注解参数注解生成了【请求对象工厂】以及【参数数据转换器
  • 通过解析方法返回类型响应数据类型生成了【请求适配器工厂】、【响应数据转换器工厂】、【请求执行器(装饰器)

4. 请求与响应

本章我们将分析请求与响应的过程,以下是对应的示例代码

call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {

    }
});
复制代码

4.1 处理回调

由上一章我们知道,这里的call实际上是装饰器ExecutorCallbackCall,我们来看下ExecutorCallbackCall.enqueue()方法的代码

// ExecutorCallAdapterFactory
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) {
        checkNotNull(callback, "callback == null");

        delegate.enqueue(new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
                callbackExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        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(new Runnable() {
                    @Override
                    public void run() {
                        callback.onFailure(ExecutorCallbackCall.this, t);
                    }
                });
            }
        });
    }

    ...
}
复制代码

ExecutorCallbackCall有两个成员变量,callbackExecutordelegate,通过之前的分析我们知道它们分别对应了MainThreadExecutorOkHttpCall。那么先来分析MainThreadExecutor.execute()方法,该方法在OkHttpCall的请求回调中被调用

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

    @Override
    public void execute(Runnable r) {
        handler.post(r);
    }
}
复制代码

这里的功能非常好理解,综合之前的代码来看就是将OkHttpCall的请求回调结果发送至主线程。再来看OkHttpCall.enqueue()方法

// OkHttpCall
@Override
public void enqueue(final Callback<T> callback) {
    okhttp3.Call call;
    call = rawCall = createRawCall();
    ...
    call.enqueue(new okhttp3.Callback() {
        @Override
        public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
            Response<T> response = parseResponse(rawResponse);
            callback.onResponse(OkHttpCall.this, response);
            ...
        }

        @Override
        public void onFailure(okhttp3.Call call, IOException e) {
            callback.onFailure(OkHttpCall.this, e);
        }
        ...
    });
}
复制代码

这里我把核心的代码摘抄出来进行分析,首先是通过createRawCall()方法获取真实的请求执行器

4.2 生成okhttp3.Call

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

这里有两个需要关注的点,一是调用callFactory.newCall()方法获取真实的请求执行器,callFactory实际上就是OkHttpClient对象的引用,这和我们在OkHttp中生成请求执行器的方法一致;二是通过requestFactory.create()方法获取请求体okhttp3.Request的实例,其中args是通过动态代理API方法拿到的传参。现在我们开始分析生成Request对象的过程

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

handlers是参数封装类ParameterHandler的集合,通过apply()方法可以处理参数数据,转换成RequestBuilder需要的格式,然后通过RequestBuilder的引用设置数据,这些数据将在生成Request时用到。先来看下RequestBuilder的构造方法

// RequestBuilder
RequestBuilder(String method, HttpUrl baseUrl,
               @Nullable String relativeUrl, @Nullable Headers headers, @Nullable MediaType contentType,
               boolean hasBody, boolean isFormEncoded, boolean isMultipart) {
    this.method = method;
    this.baseUrl = baseUrl;
    this.relativeUrl = relativeUrl;
    this.requestBuilder = new Request.Builder();
    this.contentType = contentType;
    this.hasBody = hasBody;

    if (headers != null) {
        requestBuilder.headers(headers);
    }

    if (isFormEncoded) {
        // Will be set to 'body' in 'build'.
        formBuilder = new FormBody.Builder();
    } else if (isMultipart) {
        // Will be set to 'body' in 'build'.
        multipartBuilder = new MultipartBody.Builder();
        multipartBuilder.setType(MultipartBody.FORM);
    }
}
复制代码

可以看到我们之前在解析注解、加载API方法配置的过程中生成的属性在这都得到了应用。再来看ParameterHandler.apply()的过程,我们以请求示例中定义的API方法为例,方法参数中使用了@Query注解,对应的参数封装类是Query

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

参数数据转换器在这里开始发挥作用了,可以通过调用Converter.convert()方法将参数数据转换成RequestBuilder实际需要的数据,通过3.3.2一节的分析我们知道处理String类型数据的转换器是ToStringConverter,因此这里valueConverter就是ToStringConverter实例的引用,重新回顾一下ToStringConverter.convert()方法

// BuiltInConverters.ToStringConverter
@Override
public String convert(Object value) {
    return value.toString();
}
复制代码

数据转换完毕后,继续调用RequestBuilder.addQueryParam()方法设置Query参数的数据

// RequestBuilder
void addQueryParam(String name, @Nullable String value, boolean encoded) {
    if (relativeUrl != null) {
        // Do a one-time combination of the built relative URL and the base URL.
        urlBuilder = baseUrl.newBuilder(relativeUrl);
        ...
        relativeUrl = null;
    }

    if (encoded) {
        //noinspection ConstantConditions Checked to be non-null by above 'if' block.
        urlBuilder.addEncodedQueryParameter(name, value);
    } else {
        //noinspection ConstantConditions Checked to be non-null by above 'if' block.
        urlBuilder.addQueryParameter(name, value);
    }
}
复制代码

到这里就都是OkHttp构建Request的方法了,不再展开细说。回到RequestFactory.create(),继续往下看Request的构建过程

// RequestFactory.create
return requestBuilder.get()
        .tag(Invocation.class, new Invocation(method, argumentList))
        .build();
复制代码

首先调用了RequestBuilder.get()方法,看下源码

Request.Builder get() {
    HttpUrl url;
    HttpUrl.Builder urlBuilder = this.urlBuilder;
    if (urlBuilder != null) {
        url = urlBuilder.build();
    } else {
        // No query parameters triggered builder creation, just combine the relative URL and base URL.
        //noinspection ConstantConditions Non-null if urlBuilder is null.
        url = baseUrl.resolve(relativeUrl);
        ...
    }

    RequestBody body = this.body;
    if (body == null) {
        // Try to pull from one of the builders.
        if (formBuilder != null) {
            body = formBuilder.build();
        } else if (multipartBuilder != null) {
            body = multipartBuilder.build();
        } else if (hasBody) {
            // Body is absent, make an empty body.
            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);
}
复制代码

同样这里也都是OkHttp层的调用,成员变量requestBuilder对应的类型就是okhttp3.Request.Builder,调用build()方法就可以生成Request对象了

至此OkHttpCall.createRawCall()成功创建了一个okhttp3.Call的实例,现在我们回到OkHttpCall.enqueue()方法继续往下看

4.3 处理okhttp3.Response

得到okhttp3.Call实例后,下一步就是调用Call.enqueue()发起异步请求,并在回调中得到响应体对象okhttp3.Response,由于这是OkHttp层的,因此还需要解析转换成Retrofit层的响应体对象,解析转换的方法是OkHttpCall.parseResponse()

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

这里的重点是调用ResponseConverter.convert()转换响应数据,之前分析过的内置和自定义的响应数据转换器在这发挥了作用,ResponseBody成功转换成用户需要的类型

至此我们完成了okhttp3.Response的处理过程,下一步再将生成的retrofit2.Response对象通过回调方法返回给用户,请求与响应的过程以及整个Retrofit工作流程的源码分析就完成了

4.4 本章小结

这一章分析了请求与响应的过程,主要完成了以下工作:

  • 通过上一章生成的请求执行器代理类发起异步请求
  • 通过RequestFactory构建请求体Request,其中包括使用参数数据转换器处理请求参数
  • 通过CallFactory生成真实请求执行器okhttp3.Call,并调用enqueue()方法发起真实的异步请求
  • 处理OkHttp层响应对象okhttp3.Response,生成Retrofit层响应对象retrofit2.Response,其中包括使用响应数据转换器将响应数据转换成用户定义的形式
  • 请求执行器代理类中使用回调执行器将响应结果返还给用户

三、总结

最后以一张Retrofit的工作流程图总结之前的分析(ps:为了和流程进行区分,这里我将一些重要成员抽象成了数据源)

关注下面的标签,发现更多相似文章
评论