专栏名称: Anlia
Android工程师
目录
相关文章推荐
开发者全社区  ·  京东太猛了,全体算法岗喜提 30% 普调涨薪 ·  21 小时前  
开发者全社区  ·  爽子被by了? ·  21 小时前  
开发者全社区  ·  说乾隆也溜了? ·  昨天  
开发者全社区  ·  华为的这个瓜好像是真的 ·  昨天  
开发者全社区  ·  不准加班!美的强制18点20下班;大疆强制员 ... ·  2 天前  
51好读  ›  专栏  ›  Anlia

[Android] Retrofit源码:流程解析

Anlia  · 掘金  · android  · 2019-03-23 10:10

正文

阅读 21

[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 时,集合依次添加了两个适配器工厂 CompletableFutureCallAdapterFactory ExecutorCallAdapterFactory ;当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






请到「今天看啥」查看全文