Retrofit 源码深度解析-(2)初始化
正如前一章所说,使用Retrofit
的第一步,就是初始化。初始化步骤分为Retrofit
实例初始化、Service接口
初始化等等,下面的内容将一一阐述。
2.1 初始化Retrofit
2.1.1 初始化时序图
2.1.2 new Retrofit.Builder
首先要明确目标:初始化的目的,是为了使用配置信息构建出Retrofit实例
明确这个目标,再看代码就事半功倍。
Retrofit.Builder builder = new Retrofit.Builder();
builder.client(new OkHttpClient());
builder.baseUrl("https://www.baidu.com/");
builder.addCallAdapterFactory(new DefaultCallAdapt.DefaultCallAdaptFactory());
builder.addConverterFactory(new MyConverterFactory());
Retrofit retrofit = builder.build();
第一步,是new一个Retrofit.Builder
。因为构建Retrofit
的信息比较多,良好的设计风格就是将构建步骤进行收拢,使用Build模式
关注构建的步骤。
看一下Builder
的定义
通过Builder
类的定义,大致可以了解到构建Retrofit
对象所需的信息,接下来进到方法里面查看详细的构建方式。
2.1.3 platform
Builder的无参构造函数调用了方法Platform.get()
。类在第一次使用时会被加载,而加载的时候,进行static变量的初始化,所以static变量PLATFORM
会被Platform.get()
时初始化。
Platform对象定义了一些与平台相关的配置信息。
平台指的是JVM的平台,比如Android的Dalvik虚拟机,和服务端常见的HotSpot。
虽然都是JVM,但还是有些细微的差别,比如jdk1.8提供了默认方法的特性,在android低版本上是不存在的。
根据Platform
的含义以及查看Platform
的方法定义,前几个方法就可以知道,定义是为了在不同的虚拟机下,会有一些默认的配置信息。
比如defaultCallAdapterFactories
方法内部,就判断了是否是Java8,如果是的话,还提供Java8的CompletableFuture
特性:
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
// java 8
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
其他的default开头方法也都差不多
其中重点关注的是invokeDefaultMethod
和isDefaultMethod
。
isDefaultMethod
方法会根据类属性hasJava8Types
来判断,而hasJava8Types
的设置,是在Platform
初始化时传入,如果是HotSpot则默认是(只有1.8以上才能引入Retrofit包),如果是Android,则会判断SDK版本是否 >= 24
private static Platform findPlatform() {
return "Dalvik".equals(System.getProperty("java.vm.name"))
? new Android() //
: new Platform(true);
}
Platform(boolean hasJava8Types) {
this.hasJava8Types = hasJava8Types;
// 省略一些代码
}
// android
// 构造函数
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
而invokeDefaultMethod
方法有一些特殊的是,使用LockUp
实例化Service对象
,而这个LockUp
对象用了一些不常见的方式得到
lookupConstructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);
lookupConstructor.setAccessible(true);
// 上面的代码在Platform构造函数中
有了特殊的LockUp
构造函数对象之后,就可以通过这个这个LockUp
构造函数实例化对象,传入-1
Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, Object... args)
throws Throwable {
Lookup lookup =
lookupConstructor != null
? lookupConstructor.newInstance(declaringClass, -1 /* trusted */)
: MethodHandles.lookup();
return lookup.unreflectSpecial(method, declaringClass).bindTo(object).invokeWithArguments(args);
}
关键在于传入了一个-1,而这个-1就是Lookup
定义的TRUSTED
常量的值
这一块暂时还不知道为啥,可能就是Default方法在不进行实例化的时候就是不行?我试一下。
如果使用的是默认的
MethodHandles.lookup();
则会报错
no private access for invokespecial: interface com.gonzo.study.BaiduApi, from retrofit2.Platform
有了Platform
实例之后,一些平台化的特殊操作,可以交由Platform对象执行 接下来继续回到Builder
2.1.4 callFactory
Retrofit
的定义是基于OkHttp3封装的一款轻量级的、让用户可以以定义Service的方式来轻松定义Http请求的框架。
所以框架内部肯定需要一个具体的进行Http请求
的实例,也就是OkHttp3定义的okhttp3.Call.Factory
。具体可以查看OkHttp相关Demo链接
Retrofit.Builder
提供两个方法设置
public Builder client(OkHttpClient client) {
return callFactory(Objects.requireNonNull(client, "client == null"));
}
public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = Objects.requireNonNull(factory, "factory == null");
return this;
}
一般情况下,用Builder client(OkHttpClient client)
方法设置OkHttpClient
,在设置之前, 也可以用上构建OkHttpClient
时可传入的拦截器、代理等等
2.1.5 baseUrl
该属性用作定义baseUrl
。
Retrofit
的使用方式是一个Retrofit
实例定义一个全局的baseUrl
,然后在Service
方法当中定义具体的path
。请求是使用baseUrl + path
的方式进行拼接请求。
支持多种方式传入,最终会转换成okhttp3.HttpUrl
对象
public Builder baseUrl(URL baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl.toString()));
}
public Builder baseUrl(String baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
2.1.6 converterFactories
converterFactorie
的类型为retrofit2.Converter.Factory
,看名字就知道这是一个工厂类,工厂类的作用是用来创建对象,所以这个工厂类就是用来创建Converter
对象。
查看retrofit2.Converter.Factory
的定义:
其中,getParameterUpperBound
与getRawType
用来获取参数化类型的工具方法,具体实现也是依赖于Retrofit.Utils
工具包。
/**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
/**
* Extract the raw class type from {@code type}. For example, the type representing {@code
* List<? extends Runnable>} returns {@code List.class}.
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
需要重点关注的,是responseBodyConverter()
、requestBodyConverter()
和stringConverter()
三个方法,这三个方法定义了三种转换工具类的创建。
2.1.6.1 responseBodyConverter
/**
* Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for
* response types such as {@code SimpleResponse} from a {@code Call<SimpleResponse>}
* declaration.
*/
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
返回用于将 HTTP 响应正文转换为类型的转换器,如果此工厂无法处理类型,则返回 null。
这用于为响应类型创建转换器,例如来自 Call
声明的 SimpleResponse
。
通过这段描述,可以得知两个关键信息,1、如果当前定义的Converter
类无法处理当前type
,则返回null
类型。2、创建的Converter
用于将ResponseBody
类型转换为所需要的对象
这个方法会在第一次调用Service
的方法时,解析注解之后被调用,传入当前被调用Service
方法的返回值类型(type),遍历所有Factory#responseBodyConverter
方法寻找合适的Converter
。
除了Type
,其他两个参数的定义分别为Annotation数组
和Retrofit
实例。Annotation
数组是当前被调用方法上的所有注解信息,Retrofit
则是当前Retrofit实例
。
下图是在调用responseBodyConverter()
方法时,传入对象的具体信息。
至于具体的Converter
使用场景,下面在讲到真正调用HttpClient
的call
方法时会提到。
2.1.6.2 requestBodyConverter
/**
* Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap} values.
*/
public @Nullable Converter<?, RequestBody> requestBodyConverter(
Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations,
Retrofit retrofit) {
return null;
}
跟responseBodyConverter()
方法差不多,也是定义类型转换器,但区别在于requestBodyConverter
方法用于定义将请求参数转换成RequestBody
。
例如,一般使用application/json
方式请求,会写成下面这种方式:
@GET("/")
Call<String> get3(@Body Data data);
这种情况下就需要一个转换器将Data
类型的数据转换为RequestBody
。
这个方法同responseBodyConverter
一样,在每次第一次运行Service
方法,解析方法上的注解构建RequestBuilder
时会被调用,传入参数相关信息如下:
一般情况下需要关注type
和annotations
。例如在这个场景里,可以通过判断annotation
中是否包含Body
注解,来创造一个将对象转换为json之后写入RequestBody
的转换器。
至于具体的Converter
使用场景,下面在讲到请求参数构建时会提到。
2.1.6.3 stringConverter
/**
* Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
* {@code type} cannot be handled by this factory. This is used to create converters for types
* specified by {@link Field @Field}, {@link FieldMap @FieldMap} values, {@link Header @Header},
* {@link HeaderMap @HeaderMap}, {@link Path @Path}, {@link Query @Query}, and {@link
* QueryMap @QueryMap} values.
*/
public @Nullable Converter<?, String> stringConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
返回用于将类型转换为字符串的转换器,如果此工厂无法处理类型,则返回
null
。这用于为@Field
、@FieldMap
值、@Header
、@HeaderMap
、@Path
、@Query
和@QueryMap
值指定的类型创建转换器。
通过方法注释可以得知,这个转换器是为了将@Field
、@FieldMap
值、@Header
、@HeaderMap
、@Path
、@Query
和 @QueryMap
注解对应的参数,转换为String
类型的转换器。
默认如果没有配置,则会返回一个ToStringConverter
,方法内部会简单的调用对象toString()
方法。一般情况下在使用上面这些注解时,都只会传入基础类型。
这里有一个疑问,我记得
SpringCloud
的RestTemplate
是不支持在get请求中传入一个对象的,这里估计也是不行,可以尝试扩展一下?
至于具体的Converter
使用场景,下面在讲到请求参数构建时会提到。
2.1.7 callAdapterFactories
callAdapterFactories
是一个retrofit2.CallAdapter.Factory
数组,顾名思义,是用来创建CallAdapter
的。下面是类定义
除去两个工具方法getParameterUpperBound
和getRawType
外,get
是主要关注的。
/**
* Returns a call adapter for interface methods that return {@code returnType}, or null if it
* cannot be handled by this factory.
*/
public abstract @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit);
通过实现该方法,可以自定义的关心当前类型的CallAdapter
。
至于CallAdapter
是什么,下面的章节会深入讲解,这里只需要知道CallAdapter
的定义是通过添加Factory
到Retrofit
中来的。
2.1.8 callbackExecutor
该属性为执行器。
默认情况下,在调用build
方法时,会调用Platform#defaultCallbackExecutor方
法,这个方法在Android会被重新实现:
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
同时,在build构建DefaultCallAdapterFactory
中会传入这个executor,且DefaultCallAdapterFactory
在运行期间,会判断是否存在executor从而创建一个ExecutorCallbackCall
相当于这个字段是提供给android回调用的?
2.1.9 validateEagerly
是否早期校验
该属性用于控制Service
方法是在创建Service实例时进行校验和初始化,还是在第一次调用Service方法时进行校验和初始化。
2.1.10 build
在有了初始化Retrofit
的所有信息之后,接下来就是进行组装。
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);
}
2.1.10.1 设置默认的callAdapterFactory
可以看到,除去最基本的callAdapterFactory
,这里还调用Platform
添加了基于平台的默认callAdapterFactory
。通过查看方法defaultCallAdapterFactories
:
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
可以得知,如果是java8以上的版本,会添加一个CompletableFutureCallAdapterFactory
实例,否则只有一个DefaultCallAdapterFactory
2.1.10.1.1 CompletableFutureCallAdapterFactory
该工厂是为了创建适配
CompletableFuture
类型的返回值的Convert
查看工厂的get
方法:
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 如果返回类型不是CompletableFuture 则不支持
if (getRawType(returnType) != CompletableFuture.class) {
return null;
}
// 判断返回类型是否是参数化的 不能是CompletableFuture<> 未定义的
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalStateException(
"CompletableFuture return type must be parameterized"
+ " as CompletableFuture<Foo> or CompletableFuture<? extends Foo>");
}
// 得到参数化的类型结果 比如 CompletableFuture<Foo> 就是得到 Foo
Type innerType = getParameterUpperBound(0, (ParameterizedType) returnType);
// 如果不是Response类型 则返回一个BodyCallAdapter
if (getRawType(innerType) != Response.class) {
// Generic type is not Response<T>. Use it for body-only adapter.
return new BodyCallAdapter<>(innerType);
}
// 如果是Response类型 则判断是参数化了 不能是Response<>这种未定义的
// Generic type is Response<T>. Extract T and create the Response version of the adapter.
if (!(innerType instanceof ParameterizedType)) {
throw new IllegalStateException(
"Response must be parameterized" + " as Response<Foo> or Response<? extends Foo>");
}
// 得到Response的参数化类型 然后基于这个类型构建一个ResponseCallAdapter
Type responseType = getParameterUpperBound(0, (ParameterizedType) innerType);
return new ResponseCallAdapter<>(responseType);
}
可以看到,这个工厂支持构建两种CallAdapter
,BodyCallAdapter
和ResponseCallAdapter
。至于他们的详细区别,在讲到CallAdapter
时,会列举所有典型的CallAdapter
进行一一解析。
2.1.10.1.2 DefaultCallAdapterFactory
在未进行任何特殊配置的情况下,
Retrofit
的默认adapter。居然是默认,那么就会适配平台,所以这里面也会有一些平台相关的信息
通过上面的build调用Platform
的代码,可以看到在new DefaultCallAdapterFactory
时,传入了一个executor
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
再查看DefaultCallAdapterFactory#get
方法:
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 默认只支持Call类型的返回 也就是在Service那边定义返回类型为Call<>
if (getRawType(returnType) != Call.class) {
return null;
}
// 校验是否参数化
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
}
// 获取Call<Foo> 的Foo
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
// 这是重点,判断Service上是否存在SkipCallbackExecutor注解
// 不存在的话 返回创建DefaultCallAdapterFactory构造函数传入的executor
final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
// 随后构建一个CallAdapter
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
// 这里是重点 在存在executor的情况下,会构建一个ExecutorCallbackCall返回 为了适配Android的回调
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
}
方法中除了最基本的校验之外,最需要关注的就是创建CallAdapter
时传入的executor
。在CallAdapter
被调用时,会基于是否存在executor,来断定是否构建ExecutorCallbackCall
。这一块关于CallAdapter
的在下面讲CallAdapter
时,会列举所有典型CallAdapter
一一解析。
随后回到build
流程当中,在准备好所有的配置信息之后,就可以构建Retrofit
了
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
至此,Retrofit
构建完成。
2.2 创建Service对象
Retrofit
构建完成之后,就是使用Retrofit
对象构建我们的Service
实例。回顾一下代码:
BaiduApi api = retrofit.create(BaiduApi.class)
BaiduApi定义:
public interface BaiduApi {
@GET("/")
Call<String> get1(@Query("aaa") String args);
@GET("/")
Response<String> get2(@Query("aaa") String args);
@GET("/")
Call<String> get3(@Body Data data);
@GET("/")
Call<String> get4(@Header("d") Data d2);
}
2.2.1 创建Service对象时序图
2.2.2 Retrofit#create
public <T> T create(final Class<T> service) {
// 校验
validateServiceInterface(service);
// 创建动态代理
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
// 平台信息
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 如果是Object的方法 则正常调用
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
// 判断是否是java8的default 方法
return platform.isDefaultMethod(method)
// 使用基于平台特有的执行默认方法的方式
? platform.invokeDefaultMethod(method, service, proxy, args)
// 先加载方法缓存,再执行
: loadServiceMethod(method).invoke(args);
}
});
}
create
方法分为两部分,先校验,如果通过的话,会基于传入的ServiceClass
生成一个动态代理对象返回。
2.2.3 Retrofit#validateServiceInterface
通过查看校验的相关代码,其实可以侧面了解到当前框架支持什么场景,不支持什么场景。
private void validateServiceInterface(Class<?> service) {
// 先校验是否是一个接口
if (!service.isInterface()) {
// 不是接口那肯定没得玩
throw new IllegalArgumentException("API declarations must be interfaces.");
}
// 构建一个queue
Deque<Class<?>> check = new ArrayDeque<>(1);
// 将当前校验的service添加到第一个
check.add(service);
while (!check.isEmpty()) {
// 获取第一个service class
Class<?> candidate = check.removeFirst();
// 校验接口是否定义了泛型 类型形参
if (candidate.getTypeParameters().length != 0) {
StringBuilder message =
new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
if (candidate != service) {
message.append(" which is an interface of ").append(service.getName());
}
throw new IllegalArgumentException(message.toString());
}
// 将当前接口继承的接口添加到queue中,下一次继续校验
Collections.addAll(check, candidate.getInterfaces());
}
// 是否提前校验、初始化
if (validateEagerly) { // 默认false
Platform platform = Platform.get();
// 迭代当前类的所有方法
for (Method method : service.getDeclaredMethods()) {
// 过滤掉默认方法和static方法
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
// 校验、初始化方法并添加到缓存
loadServiceMethod(method);
}
}
}
}
通过上面的校验相关代码,可以得知Retrofit
是不支持定义了类型形参的接口。例如下面的接口定义:
public interface TypeParametersTestService<A, B, C> {
A test(B b, C c);
}
在使用Retrofit#create
方法构建时,会抛出异常
java.lang.IllegalArgumentException: Type parameters are unsupported on com.gonzo.retrofit.extend.test.service.TypeParametersTestService
为什么不支持?这个可以思考一下。
如果要支持的话,缺少什么?
我觉得关键点在于,如果接口定义了类型形参,那么在创建接口的实例的过程中当中,基于接口方法的返回类型、参数类型选用对应的
Convert
将会是一件不确定的事情。所以接口必须定义明确。
校验通过之后,会判断是否需要提前校验、初始化。最终会调用Retrofit#loadServiceMethod
方法,这个在下面会展开详细描述。
2.3 Proxy#invoke
创建完Service
实例之后,接下来就是调用Service的方法:
BaiduApi api = retrofit.create(BaiduApi.class)
Call<String> call = api.get1("test");
继续回顾一下BaiduApi
的定义
public interface BaiduApi {
@GET("/")
Call<String> get1(@Query("aaa") String args);
@GET("/")
Response<String> get2(@Query("aaa") String args);
@GET("/")
Call<String> get3(@Body Data data);
@GET("/")
Call<String> get4(@Header("d") Data d2);
}
上面的create
章节讲到,返回的service对象是一个动态代理对象。熟悉动态代理的同学都知道,这个调用执行到被代理对象的invoke
方法,也就是:
public <T> T create(final Class<T> service) {
// 校验
validateServiceInterface(service);
// 创建动态代理
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
// 平台信息
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 如果是Object的方法 则正常调用
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
// 判断是否是java8的default 方法
return platform.isDefaultMethod(method)
// 使用基于平台特有的执行默认方法的方式
? platform.invokeDefaultMethod(method, service, proxy, args)
// 先加载方法缓存,再执行
: loadServiceMethod(method).invoke(args);
}
});
}
可以看到invoke
方法最核心的是最后三句代码。
首先调用platform
对象,判断当前方法是否是一个默认方法。这个判断在最开始初始化讲解platform
时提到过,内部会根据平台信息判断是否支持默认方法的调用(android平台下是判断sdk api版本)
如果是default
方法,再使用Lockup
进行调用。这一步涉及到java8的默认方法的一些细节,具体可以查看2.1.3相关信息了解。
如果是非default
方法,则会调用Retrofit#loadServiceMethod
获取ServiceMethod
实例,并执行invoke
。
2.3.1 Retrofit#loadServiceMethod
在Retrofit
的对象当中,有一个serviceMethodCache
属性,该属性是一个ConcurrentHashMap
类型的集合,用作缓存那些已经被加载的ServiceMethod
实例。
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;
}
如果缓存不存在,则调用ServiceMethod#parseAnnotations
方法进行解析,缓存之后再返回。
2.3.2 ServiceMethod
Retrofit#loadServiceMethod
方法的返回类型为ServiceMethod
,该对象定义从名字可以看出来,是对Service的方法的抽象。
查看ServiceMethod
的定义:
可以看到有两个关键的方法invoke
和parseAnnotations
。其中parseAnnotations
是一个static
方法,通过方法签名可以大概揣测到这是一个提供创建ServiceMethod
实例的工厂方法
。
事实也是如此,Retrofit#loadServiceMethod
就是通过调用ServiceMethod#parseAnnotations
来获取ServiceMethod
实例。
同时ServiceMethod
有几个实现类
其中HttpServiceMethod
继承自ServiceMethod
,而CallAdapted
、SuspendForResponse
和SuspendForBody
继承自HttpServiceMethod
。
具体UML图如下:
其中HttpServiceMethod
实现了ServiceMethod
的invoke
方法
@Override
final @Nullable ReturnT invoke(Object[] args) {
// 创建一个OkHttpCall对象
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
// 转到adapt方法执行
return adapt(call, args);
}
而HttpServiceMethod
自己定义了adapt
方法供子类实现
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
CallAdapted
、SuspendForResponse
和SuspendForBody
都实现了HttpServiceMethod
的adapt
方法。
2.3.2.1 SuspendForResponse和SuspendForBody
这两个其实是Kotlin相关支持的ServiceMethod
,具体特性由于对kotlin不是很熟悉,所以就不多说了。
2.3.2.2 CallAdapted
在默认的服务端开发情况下,返回的ServiceMethod
实例都是这个类型。这个类的定义也很简单,起到一个适配的作用:
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
// 转到CallAdapter执行
return callAdapter.adapt(call);
}
}
知道类的大概结构和关系图之后,接下来开始深入到parseAnnotations
方法,来详细捋一捋是如何创建ServiceMethod
对象的。
2.3.2.3 parseAnnotations
先看一下这个静态方法的代码
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 解析方法注解 构建出一个RequestFactory
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
// 获取方法的正式返回值类型 例如List<String> 返回的就是 List<String> 而不是List
Type returnType = method.getGenericReturnType();
// 判断是否还存在未明确的类型 例如List<?>、T、List<? extend Object> 等等
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
// void返回值也是不支持的
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
// 转到 HttpServiceMethod#parseAnnotations
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
- 先调用
RequestFactory#parseAnnotations
得到RequestFactory对象,该对象就是作在service方法调用时,根据参数进行构建出Request
的对象。具体的内部详细实现逻辑,下面会进行讲解。 - 进行校验,判断方法的返回类型是否是明确的,比如不能是
List<?>
、T
、List<? extend Object>
等等。这些对应的类型在Java当中都有对应的类表示(GenericArrayType、TypeVariable、WildcardType可以看我的另外一篇博客)。同时返回类型也不能是void。 - 校验通过之后,跳到
HttpServiceMethod#parseAnnotations
:
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
// 判断是否是kotlin
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
// 定义adapter的类型
Type adapterType;
if (isKotlinSuspendFunction) {
// kotlin 相关处理 略过
} else {
// Java 处理 直接获取方法的正式返回类型 List<String>
adapterType = method.getGenericReturnType();
}
// 获取CallAdapter
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
// CallAdapter的responseType
Type responseType = callAdapter.responseType();
// CallAdapter不支持直接返回okhttp3.Response类型 算是一个限制
if (responseType == okhttp3.Response.class) {
throw methodError(
method,
"'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
// Response的class定义为Response<T>,所以不能直接返回 Response 而是需要指定Response的类型形参
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
// HEAD类型的请求 CallAdapter的responseType必须是Void类型 这是为啥? 可是前面不是判断方法的返回值不能为Void吗
// 噢,是不能为void 但是可以为Void....
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
// 获取responseConverter
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
// 非kotlin 返回一个CallAdapted实例
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
// kotlin 相关处理 ...
}
忽略kotlin的相关处理,核心流程有如下几个
- 获取方法的返回类型,用作查询
CallAdapter
所支持的type类型传入。 - 校验
CallAdapter
的返回类型,不能是okhttp3.Response
,也不能是未定义详细类型的Response
。 - 根据
CallAdapter
所定义的responseType
,获取ResponseConvert
。 - 使用
requestFactory
、callFactory
、responseConverter
和callAdapter
new一个CallAdapted
实例返回。
通过以上的流程,可以了解到,方法的返回类型决定了CallAdapter
的类型(所以CallAdapter
会有很多实现类,用来支持Java8、RxJava等等),而CallAdapter
的responseType
决定了responseConverter
的类型。
接下来针对每一个流程进行深入
2.3.3 RequestFactory
调用ServiceMethod#parseAnnotations
方法的第一步,就调用了RequestFactory#parseAnnotations
方法,接下来针对这个方法进行解析,看看这个方法内部到底做了什么。
在去分析RequestFactory
时,换个角度思考,当我们要自己去实现一个类似的Http请求的框架时,肯定是会将构造okhttp3.Request
的代码进行抽取,在每次调用Service方法发起Http请求时,使用方法上的注解信息、参数信息构建出一个okhttp3.Request
。当然,实际情况下会考虑很多特殊情况,但大体思路是对的。
先看看RequestFactory
的定义
可以看到RequestFactory
类定义了创建Request
需要的信息(方法、url、param、header等等)。同时由于这些信息都是通过Service方法上的注解上解析得到了,所以针对解析、创建RequestFactory
这个步骤,交由RequestFactory
内部的Builder
处理
进入RequestFactory.parseAnnotations
方法后,熟悉的套路
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
创建了一个Builder
,将RequestFactory
的构建步骤给流程化了了。
2.3.3.1 RequestFactory.Builder
通过上面的Builder
的UML图可以看到,Builder
类当中包含大量的配置字段,这些字段看名字大概都能猜到什么意思。而Builder
的处理流程,就是将方法上的信息转换成Builder
的配置字段,最终根据配置字段构建出RequestFactory
实例返回。
一部分字段的值通过构造函数确定:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
现在开始进入Builder#build
方法:
RequestFactory build() {
// 解析方法的注解 GET POST HEAD 等等注解
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];
// 解析参数信息,转换成ParameterHandler类型
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);
}
2.3.3.1.1 解析注解信息
先回顾一下之前定义的BaiduApi
:
public interface BaiduApi {
@GET("/")
Call<String> get1(@Query("aaa") String args);
}
可以看到,我们需要构建的Request
信息,是通过方法的注解、方法返回值、参数的注解和参数信息得到的。
所以先从解析方法注解开始
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.");
}
// 是一个Multipart请求
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
// 是一个Form请求
isFormEncoded = true;
}
}
注解信息分为两部分:请求方式如GET、POST等等,配置信息如Headers、Multipart和FormUrlEncoded。
请求方式的相关注解都会被转到parseHttpMethodAndPath
方法执行
Headers相关解析会转到parseHeaders方法执行
而Multipart和FormUrlEncoded则会影响isMultipart和isFormEncoded的值
2.3.3.1.2 parseHttpMethodAndPath
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
// 避免重复设置
if (this.httpMethod != null) {
throw methodError(
method,
"Only one HTTP method is allowed. Found: %s and %s.",
this.httpMethod,
httpMethod);
}
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
return;
}
// Get the relative URL path and existing query string, if present.
int question = value.indexOf('?');
if (question != -1 && question < value.length() - 1) {
// Ensure the query string does not have any named parameters.
// 避免出现 ?aaa={aaa}的用法
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;
// 解析path上的请求 如: /aaa/bbb/{id}/ccc 中的id
this.relativeUrlParamNames = parsePathParameters(value);
}
通过这一步,确定httpMethod、hasBody、relativeUrl和relativeUrlParamNames。
2.3.3.1.3 parseHeaders
@Headers
注解也是方法注解,其用法为
public interface BaiduApi {
@GET("/")
@Headers({"contentType:applicationJson"})
Call<String> get1(@Query("aaa") String args);
}
对应的解析代码:
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);
}
// key
String headerName = header.substring(0, colon);
// value
String headerValue = header.substring(colon + 1).trim();
// 针对Content-Type的特殊处理 这个关系到当前请求的请求类型
if ("Content-Type".equalsIgnoreCase(headerName)) {
try {
contentType = MediaType.get(headerValue);
} catch (IllegalArgumentException e) {
throw methodError(method, e, "Malformed content type: %s", headerValue);
}
} else {
// 否则添加到builder当中
builder.add(headerName, headerValue);
}
}
// build
return builder.build();
}
解析代码也很平常,就是针对Content-Type
类型做了特殊处理,其他情况下使用OkHttp3
的Headers.builder
进行Headers
的构建。
经过以上几个步骤,方法上的相关注解都解析完成了,现在开始参数注解解析,这也是最复杂的部分。
2.3.3.1.4 解析参数注解信息
回顾上面的build
方法的代码片段:
// parameterAnnotationsArray 是在构建Builder时,通过method.getParameterAnnotations();得到的
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);
}
可以看到,每一个参数以及参数对应的位置信息、注解信息被包装成了一个ParameterHandler
对象
abstract class ParameterHandler<T> {
abstract void apply(RequestBuilder builder, @Nullable T value) throws IOException;
}
ParameterHandler
的定义,就是将对应的param基于规则进行转换。可能说起来有点模糊,下面会详细说明。
回到build#parseParameter
方法,解析得到ParameterHandler
对象:
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
// 循环解析annotation
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;
}
}
// 避免出现类似于 Call<String> get10(@Path("aaa") String args, String args2, @Path("bbb") String args3);
// 这种第二个参数没有注解的情况出现
// 感觉这个应该可以不用管吧?可能是为了避免错误使用?
if (result == null) {
if (allowContinuation) {
try {
if (Utils.getRawType(parameterType) == Continuation.class) {
isKotlinSuspendFunction = true;
return null;
}
} catch (NoClassDefFoundError ignored) {
}
}
throw parameterError(method, p, "No Retrofit annotation found.");
}
return result;
}
继续查看parseParameterAnnotation
:
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
// 代码特别长.....
}
由于代码太长,且内部都是if else,所以这里进行截取片段的方式一个个讲解。
2.3.3.1.5 Url
用法:
Call<String> get12(@Url String url);
解析:
if (annotation instanceof Url) {
// 校验当前参数的类型是否是明确的,不能是List<?> 这种
validateResolvableType(p, type);
// 避免重复设置
if (gotUrl) {
throw parameterError(method, p, "Multiple @Url method annotations found.");
}
// @Path不能和@Url一起用
if (gotPath) {
throw parameterError(method, p, "@Path parameters may not be used with @Url.");
}
// @Url必须在@Query之前
if (gotQuery) {
throw parameterError(method, p, "A @Url parameter must not come after a @Query.");
}
// @Url必须在@QueryName之前
if (gotQueryName) {
throw parameterError(method, p, "A @Url parameter must not come after a @QueryName.");
}
// @Url必须在@QueryMap之前
if (gotQueryMap) {
throw parameterError(method, p, "A @Url parameter must not come after a @QueryMap.");
}
// 不能跟GET POST等方法注解冲突
if (relativeUrl != null) {
throw parameterError(method, p, "@Url cannot be used with @%s URL", httpMethod);
}
gotUrl = true;
if (type == HttpUrl.class
|| type == String.class
|| type == URI.class
|| (type instanceof Class && "android.net.Uri".equals(((Class<?>) type).getName()))) {
return new ParameterHandler.RelativeUrl(method, p);
} else {
throw parameterError(
method,
p,
"@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
}
}
可以看到,在做了一些规则校验之后,生成了一个RelativeUrl
实例
static final class RelativeUrl extends ParameterHandler<Object> {
private final Method method;
private final int p;
RelativeUrl(Method method, int p) {
this.method = method;
this.p = p;
}
@Override
void apply(RequestBuilder builder, @Nullable Object value) {
if (value == null) {
throw Utils.parameterError(method, p, "@Url parameter is null.");
}
builder.setRelativeUrl(value);
}
}
通过RelativeUrl
的apply
方法的实现,大概就能明白ParameterHandler
的定义:将Request
的构建中,方法上的参数的转换交由一个个对应的ParameterHandler
实现。
就像是上面的RelativeUrl
,基于@Url
注解得到,通过调用apply
方法,将@Url
注解对应的参数的值设置为relativeUrl
。
继续回到参数解析
2.3.3.1.6 Path
用法:
@GET("/{aaa}/?aaa=c")
Call<String> get10(@Path("aaa") String args, String args2, @Path("bbb") String args3);
解析代码:
else if (annotation instanceof Path) {
validateResolvableType(p, type);
// 不能在@Query之后
if (gotQuery) {
throw parameterError(method, p, "A @Path parameter must not come after a @Query.");
}
// 不能在@QueryName之后
if (gotQueryName) {
throw parameterError(method, p, "A @Path parameter must not come after a @QueryName.");
}
// 不能在@QueryMap之后
if (gotQueryMap) {
throw parameterError(method, p, "A @Path parameter must not come after a @QueryMap.");
}
// 不能和@Url一起食用
if (gotUrl) {
throw parameterError(method, p, "@Path parameters may not be used with @Url.");
}
// 必须和relativeUrl一起食用
if (relativeUrl == null) {
throw parameterError(
method, p, "@Path can only be used with relative url on @%s", httpMethod);
}
gotPath = true;
Path path = (Path) annotation;
String name = path.value();
validatePathName(p, name);
// 获取一个StringConverter 默认是BuiltInConverters.ToStringConverter类型
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
// 构建一个ParameterHandler.Path实例
return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());
}
在进行@Path
注解使用的一些限制校验之后,从Retrofit
实例中获取到StringConverter
,构建出一个ParameterHandler.Path
实例:
static final class Path<T> extends ParameterHandler<T> {
private final Method method;
private final int p;
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Path(Method method, int p, String name, Converter<T, String> valueConverter, boolean encoded) {
this.method = method;
this.p = p;
this.name = Objects.requireNonNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override
void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) {
throw Utils.parameterError(
method, p, "Path parameter \"" + name + "\" value must not be null.");
}
builder.addPathParam(name, valueConverter.convert(value), encoded);
}
}
而Path#apply
方法内部通过调用RequestBuilder#addPathParam
来达到替换path当中的占位符的效果
void addPathParam(String name, String value, boolean encoded) {
if (relativeUrl == null) {
// The relative URL is cleared when the first query parameter is set.
throw new AssertionError();
}
String replacement = canonicalizeForPath(value, encoded);
// replace方法替换
String newRelativeUrl = relativeUrl.replace("{" + name + "}", replacement);
if (PATH_TRAVERSAL.matcher(newRelativeUrl).matches()) {
throw new IllegalArgumentException(
"@Path parameters shouldn't perform path traversal ('.' or '..'): " + value);
}
// 然后设置为新的
relativeUrl = newRelativeUrl;
}
2.3.3.1.7 Query
使用方式:
@GET("/")
Call<String> get1(@Query("aaa") String args);
@GET("/")
Call<String> get13(@Query("aaa") List<String> args);
@GET("/")
Call<String> get14(@Query("aaa") List<?> args); // 错误用法
@GET("/")
Call<String> get15(@Query("aaa") String[] args);
解析:
else if (annotation instanceof Query) {
// 避免未确定的参数类型
validateResolvableType(p, type);
Query query = (Query) annotation;
String name = query.value();
boolean encoded = query.encoded();
// rowType是外层的类型,例如List<String> 的rowType就是List
Class<?> rawParameterType = Utils.getRawType(type);
gotQuery = true;
if (Iterable.class.isAssignableFrom(rawParameterType)) {
// ParameterizedType的类型代表的是 例如 List<String> 这种整个类型
if (!(type instanceof ParameterizedType)) {
// 不能是 List 这种未指定具体类型的
throw parameterError(
method,
p,
rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ "<String>)");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
// 获取到List<String> 当中的String类型
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
// 构建一个ParameterHandler.Query对象
return new ParameterHandler.Query<>(name, converter, encoded)
// 转换成适配iterable的ParameterHandler
.iterable();
} else if (rawParameterType.isArray()) {
// 数组类型
// 装箱
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
// 构建一个ParameterHandler.Query对象
return new ParameterHandler.Query<>(name, converter, encoded)
// 转换成适配array的ParameterHandler
.array();
} else {
// 最简单的toString
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
// 构建一个ParameterHandler.Query对象
return new ParameterHandler.Query<>(name, converter, encoded);
}
}
解析Query
的步骤有三个分支,Iterable
参数、Array
参数和普通参数。
其中Iterable
参数和Array
有一个特殊的调用为
return new ParameterHandler.Query<>(name, converter, encoded).iterable();` 和`return new ParameterHandler.Query<>(name, converter, encoded).array();
通过查看ParameterHandler
对应方法的定义:
final ParameterHandler<Iterable<T>> iterable() {
return new ParameterHandler<Iterable<T>>() {
@Override
void apply(RequestBuilder builder, @Nullable Iterable<T> values) throws IOException {
if (values == null) return; // Skip null values.
for (T value : values) {
ParameterHandler.this.apply(builder, value);
}
}
};
}
final ParameterHandler<Object> array() {
return new ParameterHandler<Object>() {
@Override
void apply(RequestBuilder builder, @Nullable Object values) throws IOException {
if (values == null) return; // Skip null values.
for (int i = 0, size = Array.getLength(values); i < size; i++) {
//noinspection unchecked
ParameterHandler.this.apply(builder, (T) Array.get(values, i));
}
}
};
}
这两个方法相当于创建一个适配器,以一种优雅的方式解决了Array
和Iterable
类型的兼容。
因为默认情况下ParameterHandlerl
理解为处理一个单一的对象,但确实有集合类型的对象需要处理,如果为了兼容集合类型要么就是在每一个ParameterHandler
实现类当中针对类型做判断,然后走集合的处理或者单一对象的处理,要么就是用现在这个吊炸天的方式,写一个基于单一ParameterHandler
的集合适配。
这个代码还是很吊的,我就写不出来,一开始看了半天,没太明白这个是解决什么的。这个思路可以好好学习下。
可以参考一下写个Demo
public abstract class Join<T> {
abstract void join(T t);
Join<Iterable<T>> iterable() {
return new Join<Iterable<T>>() {
@Override
void join(Iterable<T> tIterable) {
for (T t : tIterable) {
Join.this.join(t);
}
}
};
}
static class JoinImpl extends Join<String> {
@Override
void join(String s) {
System.out.println(s);
}
}
public static void main(String[] args) {
Join<Iterable<String>> join = new JoinImpl().iterable();
join.join(Arrays.asList("1", "2", "3", "4", "5"));
/**
1
2
3
4
5
*/
}
}
很牛批
2.3.3.1.8 QueryName
用法:
@GET("/test")
Call<String> get16(@QueryName String args); // api.get16("get") = /test?get
@GET("/test")
Call<String> get17(@QueryName String[] args);// api.get16("get", "set") = /test?get&set
这个好像用的不多,但是一些特殊的语法查询会用到。
解析代码:
else if (annotation instanceof QueryName) {
// 校验类型
validateResolvableType(p, type);
QueryName query = (QueryName) annotation;
boolean encoded = query.encoded();
// 得到List<String> 的List这个类型
Class<?> rawParameterType = Utils.getRawType(type);
gotQueryName = true;
// 如果是集合
if (Iterable.class.isAssignableFrom(rawParameterType)) {
// 那么是不是还没确定类型
if (!(type instanceof ParameterizedType)) {
throw parameterError(
method,
p,
rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ "<String>)");
}
// 得到参数化的类型 List<String> 的List<String>这个类型
ParameterizedType parameterizedType = (ParameterizedType) type;
// 获取List<String> 的String这个类型
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
// 老套路 new 一个ParameterHandler.QueryName 然后调用iterable的优雅处理
return new ParameterHandler.QueryName<>(converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
// 集合
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.QueryName<>(converter, encoded).array();
} else {
// 普通的String
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.QueryName<>(converter, encoded);
}
}
看一下QueryName
的代码:
static final class QueryName<T> extends ParameterHandler<T> {
private final Converter<T, String> nameConverter;
private final boolean encoded;
QueryName(Converter<T, String> nameConverter, boolean encoded) {
this.nameConverter = nameConverter;
this.encoded = encoded;
}
@Override
void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) return; // Skip null values.
// 通过转换器转换后调用RequestBuilder#addQueryParam方法 这里重点在于传入的value 是一个null
builder.addQueryParam(nameConverter.convert(value), null, encoded);
}
}
查看RequestBuilder#addQueryParam
方法
void addQueryParam(String name, @Nullable String value, boolean encoded) {
// 得到最新的urlBuilder
if (relativeUrl != null) {
// Do a one-time combination of the built relative URL and the base URL.
urlBuilder = baseUrl.newBuilder(relativeUrl);
if (urlBuilder == null) {
throw new IllegalArgumentException(
"Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
}
relativeUrl = null;
}
// 使用urlBuilder添加 QueryParameter
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);
}
}
2.3.3.1.9 QueryMap
用法:
@GET("/test")
Call<String> get18(@QueryMap Map<String, String> queryMap);
// 例如 调用api.get18(Maps.asMap("a", "b", "a1", "b1")) 则到结果 /test?a=b&a1=b1
解析代码:
else if (annotation instanceof QueryMap) {
// 校验类型
validateResolvableType(p, type);
Class<?> rawParameterType = Utils.getRawType(type);
gotQueryMap = true;
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(method, p, "@QueryMap parameter type must be Map.");
}
// 获取Map类型
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(
method, p, "Map must include generic types (e.g., Map<String, String>)");
}
// 校验是否存在未定义的类型
ParameterizedType parameterizedType = (ParameterizedType) mapType;
// 得到Map<Object, String>的 Object
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
// key只支持String
if (String.class != keyType) {
throw parameterError(method, p, "@QueryMap keys must be of type String: " + keyType);
}
// 得到得到Map<Object, String>的 String
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
// 老套路
return new ParameterHandler.QueryMap<>(
method, p, valueConverter, ((QueryMap) annotation).encoded());
}
看一下ParameterHandler.QueryMap
的实现:
static final class QueryMap<T> extends ParameterHandler<Map<String, T>> {
private final Method method;
private final int p;
private final Converter<T, String> valueConverter;
private final boolean encoded;
QueryMap(Method method, int p, Converter<T, String> valueConverter, boolean encoded) {
this.method = method;
this.p = p;
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override
void apply(RequestBuilder builder, @Nullable Map<String, T> value) throws IOException {
if (value == null) {
throw Utils.parameterError(method, p, "Query map was null");
}
// 迭代
for (Map.Entry<String, T> entry : value.entrySet()) {
String entryKey = entry.getKey();
// 校验
if (entryKey == null) {
throw Utils.parameterError(method, p, "Query map contained null key.");
}
T entryValue = entry.getValue();
if (entryValue == null) {
throw Utils.parameterError(
method, p, "Query map contained null value for key '" + entryKey + "'.");
}
// 调用类型转换器进行转换成String类型的
String convertedEntryValue = valueConverter.convert(entryValue);
if (convertedEntryValue == null) {
throw Utils.parameterError(
method,
p,
"Query map value '"
+ entryValue
+ "' converted to null by "
+ valueConverter.getClass().getName()
+ " for key '"
+ entryKey
+ "'.");
}
// 调用 RequestBuilder#addQueryParam方法
builder.addQueryParam(entryKey, convertedEntryValue, encoded);
}
}
}
可以看到,内部最终还是同Query
、QueryName
一样,调用RequestBuilder#addQueryParam
添加query参数。
2.3.3.1.10 Header
使用方式:
@GET("/")
Call<String> get4(@Header("d") Data d2);
解析代码:
else if (annotation instanceof Header) {
// 剔除掉一些校验代码
Header header = (Header) annotation;
String name = header.value();
Class<?> rawParameterType = Utils.getRawType(type);
if (Iterable.class.isAssignableFrom(rawParameterType)) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
// 实例化ParameterHandler.Header
return new ParameterHandler.Header<>(name, converter).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
// 实例化ParameterHandler.Header
return new ParameterHandler.Header<>(name, converter).array();
} else {
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
// 实例化ParameterHandler.Header
return new ParameterHandler.Header<>(name, converter);
}
}
看看ParameterHandler.Header
的定义:
static final class Header<T> extends ParameterHandler<T> {
// 剔除构造函数等定义
@Override
void apply(RequestBuilder builder, @Nullable T value) throws IOException {
// 简化校验等代码
String headerValue = valueConverter.convert(value);
builder.addHeader(name, headerValue);
}
}
最终还是调用的RequestBuilder#addHeader
,上面已经介绍过了。
2.3.3.1.11 HeaderMap
使用方式:
@GET("/")
Call<String> get19(@HeaderMap Map<String, String> headerMap);
解析代码:
else if (annotation instanceof HeaderMap) {
// 简化一下 剔除了校验的代码
Class<?> rawParameterType = Utils.getRawType(type);
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
ParameterizedType parameterizedType = (ParameterizedType) mapType;
// 获取key value的类型
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
// 得到value转换器
Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
// 构建HeaderMap的ParameterHandler
return new ParameterHandler.HeaderMap<>(method, p, valueConverter);
}
查看ParameterHandler.HeaderMap
的定义:
static final class HeaderMap<T> extends ParameterHandler<Map<String, T>> {
// 移除构造函数等代码
@Override
void apply(RequestBuilder builder, @Nullable Map<String, T> value) throws IOException {
for (Map.Entry<String, T> entry : value.entrySet()) {
String headerName = entry.getKey();
T headerValue = entry.getValue();
builder.addHeader(headerName, valueConverter.convert(headerValue));
}
}
}
可以看到,同Header
一样,最终还是调用的RequestBuilder#addHeader
。
2.3.3.1.12 Field
使用方式:
@POST("/")
Call<String> get20(@Field("name") String field);
这个是配合普通的post
application/x-www-form-urlencoded
请求,表单提交用的。类似于:
POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8
title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3
解析代码:
else if (annotation instanceof Field) {
// 移除了校验代码
Field field = (Field) annotation;
String name = field.value();
boolean encoded = field.encoded();
// 设置标志位
gotField = true;
Class<?> rawParameterType = Utils.getRawType(type);
if (Iterable.class.isAssignableFrom(rawParameterType)) {
// 集合类型
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
// new一个ParameterHandler.Field 并对集合类型适配
return new ParameterHandler.Field<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
// new一个ParameterHandler.Field 并对数组类型适配
return new ParameterHandler.Field<>(name, converter, encoded).array();
} else {
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
// new一个ParameterHandler.Field
return new ParameterHandler.Field<>(name, converter, encoded);
}
}
进入ParameterHandler.Field
查看定义:
static final class Field<T> extends ParameterHandler<T> {
// 移除构造函数等无关代码
@Override
void apply(RequestBuilder builder, @Nullable T value) throws IOException {
String fieldValue = valueConverter.convert(value);
// 最终转到了RequestBuilder#addFormField方法
builder.addFormField(name, fieldValue, encoded);
}
}
继续查看RequestBuilder#addFormField
:
void addFormField(String name, String value, boolean encoded) {
if (encoded) {
formBuilder.addEncoded(name, value);
} else {
formBuilder.add(name, value);
}
}
最终使用了okhttp3
的FormBody.Builder
进行form的field添加。
2.3.3.1.13 FieldMap
使用方式:
@POST("/")
Call<String> get21(@FieldMap Map<String, String> headerMap);
同Field
的区别就在于参数传递的差别
解析代码:
else if (annotation instanceof FieldMap) {
// ... 移除了一些校验代码
Class<?> rawParameterType = Utils.getRawType(type);
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
ParameterizedType parameterizedType = (ParameterizedType) mapType;
// 获取key value类型
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
// 设置标志位
gotField = true;
// mew ParameterHandler.FieldMap
return new ParameterHandler.FieldMap<>(
method, p, valueConverter, ((FieldMap) annotation).encoded());
}
继续查看ParameterHandler.FieldMap
定义:
static final class FieldMap<T> extends ParameterHandler<Map<String, T>> {
// 构造函数等定义
@Override
void apply(RequestBuilder builder, @Nullable Map<String, T> value) throws IOException {
for (Map.Entry<String, T> entry : value.entrySet()) {
// 移除了一些校验代码 保留核心逻辑
String entryKey = entry.getKey();
T entryValue = entry.getValue();
String fieldEntry = valueConverter.convert(entryValue);
builder.addFormField(entryKey, fieldEntry, encoded);
}
}
}
同样的,转到了RequestBuilder#addFormField
执行。
2.3.3.1.14 Part
使用方式:
@POST("/")
Call<String> get22(@Part("file") RequestBody request);
@POST("/")
Call<String> get22(@Part Part part);
一般是用来文件上传的请求方式。且@Part
注解和MultipartBody.Part
对象不能同时使用
解析代码:
else if (annotation instanceof Part) {
if (!isMultipart) {
// Part一定要跟Multipart注解 否则抛出异常
}
Part part = (Part) annotation;
gotPart = true;
String partName = part.value();
Class<?> rawParameterType = Utils.getRawType(type);
if (partName.isEmpty()) {
// 未设置Part注解的名称的情况下 需要参数类型为 MultipartBody.Part
if (Iterable.class.isAssignableFrom(rawParameterType)) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
if (!MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
// @Part注解对应的参数必须是Part类型 否则抛出异常
}
// 使用ParameterHandler.RawPart 这是一个单例类 内部因为不需要关心处理具体参数是啥,所以就成了一个工具类
return ParameterHandler.RawPart.INSTANCE.iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = rawParameterType.getComponentType();
if (!MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
// @Part注解对应的参数必须是Part类型 否则抛出异常
}
// 同上 给一个处理MultipartBody.Part类型的处理类
return ParameterHandler.RawPart.INSTANCE.array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
// 同上
return ParameterHandler.RawPart.INSTANCE;
} else {
// @Part注解对应的参数必须是Part类型 否则抛出异常
}
} else {
// Part注解上的name 参数不为空
// 需要设置header
Headers headers =
Headers.of(
"Content-Disposition",
"form-data; name=\"" + partName + "\"",
"Content-Transfer-Encoding",
part.encoding());
if (Iterable.class.isAssignableFrom(rawParameterType)) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
// 校验参数类型 如果@Part注解设置了name 则参数类型不能是MultipartBody.Part 两个不能通用 抛出异常
}
// 这里跟之前不一样的地方在于 使用了RequestBodyConverter 而不是StringConverter
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations);
// 构建ParameterHandler.Part实例
return new ParameterHandler.Part<>(method, p, headers, converter).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
if (MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
// 校验参数类型 如果@Part注解设置了name 则参数类型不能是MultipartBody.Part 两个不能通用
}
// 使用了RequestBodyConverter
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(arrayComponentType, annotations, methodAnnotations);
return new ParameterHandler.Part<>(method, p, headers, converter).array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
// 校验参数类型 如果@Part注解设置了name 则参数类型不能是MultipartBody.Part 抛出异常
} else {
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(type, annotations, methodAnnotations);
return new ParameterHandler.Part<>(method, p, headers, converter);
}
}
}
@Part
的解析代码有一个特殊的地方在于@Part
的使用规则是如果设置了@Part
注解的name,则参数不能是Part
类型。
同时,针对Part
类型的参数,直接简单的使用ParameterHandler.RawPart
单个实例处理apple请求:
static final class RawPart extends ParameterHandler<MultipartBody.Part> {
static final RawPart INSTANCE = new RawPart();
@Override
void apply(RequestBuilder builder, @Nullable MultipartBody.Part value) {
builder.addPart(value);
}
}
进入RequestBuilder#addPart查看:
void addPart(MultipartBody.Part part) {
multipartBuilder.addPart(part);
}
而对于非Part
类型的参数,则需要提供RequestBoddConvert
进行对象转换成RequestBody
类型:
static final class Part<T> extends ParameterHandler<T> {
// 略过构造函数等代码
@Override
void apply(RequestBuilder builder, @Nullable T value) {
RequestBody body;
try {
// 使用RequestBodyConvert进行对象转换
body = converter.convert(value);
} catch (IOException e) {
throw Utils.parameterError(method, p, "Unable to convert " + value + " to RequestBody", e);
}
builder.addPart(headers, body);
}
}
转换完成之后,调用RequestBuilder#addPart
方法,内部最终也是构建成一个Part
,同上面一样。
2.3.3.1.15 PartMap
使用方式:
@POST("/")
Call<String> get24(@PartMap Map<String, RequestBody> partMap);
解析代码同Part
的差别不大,无非是一个是1 一个是多而已。
2.3.3.1.16 Body
使用方式:
@GET("/")
Call<String> get3(@Body Data data);
解析代码:
else if (annotation instanceof Body) {
// 如果是@Body注解 则肯定不能使用 FormEncoded和Multipart
if (isFormEncoded || isMultipart) {
throw parameterError(
method, p, "@Body parameters cannot be used with form or multi-part encoding.");
}
// 避免重复Body
if (gotBody) {
throw parameterError(method, p, "Multiple @Body method annotations found.");
}
Converter<?, RequestBody> converter;
try {
// 获取requestBodyConverter
converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations);
} catch (RuntimeException e) {
// Wide exception range because factories are user code.
throw parameterError(method, e, p, "Unable to create @Body converter for %s", type);
}
gotBody = true;
// 得到ParameterHandler.Body
return new ParameterHandler.Body<>(method, p, converter);
}
在实际的场景当中,我们使用Body
时,都是以application/json
方式进行数据传入,那么就需要一个转换器将对象转换为json。最后构建一个ParameterHandler.Body
:
static final class Body<T> extends ParameterHandler<T> {
@Override
void apply(RequestBuilder builder, @Nullable T value) {
RequestBody body;
try {
// 数据转换
body = converter.convert(value);
} catch (IOException e) {
throw Utils.parameterError(method, e, p, "Unable to convert " + value + " to RequestBody");
}
// 调用RequestBuilder#setBody
builder.setBody(body);
}
}
进入RequestBuilder#setBody
:
void setBody(RequestBody body) {
this.body = body;
}
2.3.3.1.17 Tag
使用方式:
@GET("/")
Call<String> get25(@Tag String tag);
解析代码:
else if (annotation instanceof Tag) {
Class<?> tagType = Utils.getRawType(type);
for (int i = p - 1; i >= 0; i--) {
ParameterHandler<?> otherHandler = parameterHandlers[i];
if (otherHandler instanceof ParameterHandler.Tag
&& ((ParameterHandler.Tag) otherHandler).cls.equals(tagType)) {
// 避免重复
throw parameterError(
method,
p,
"@Tag type "
+ tagType.getName()
+ " is duplicate of parameter #"
+ (i + 1)
+ " and would always overwrite its value.");
}
}
return new ParameterHandler.Tag<>(tagType);
进入ParameterHandler.Tag:
static final class Tag<T> extends ParameterHandler<T> {
@Override
void apply(RequestBuilder builder, @Nullable T value) {
builder.addTag(cls, value);
}
}
至此,所有的HTTP相关注解全部解析完成。
这一部分,解析不同注解的代码思路基本相同,除去规则校验之外,就是将注解信息等元数据转换成ParameterHandler
对象,等待RequestBuild
进行调用时,将对应参数根据生成的ParameterHandler
,以不同的规则将参数转换成RequestBuilder
所能使用的参数。
最后,回到RequestFactory.Builder#build
方法,执行关键的new RequestFactory(this);
就得到了我们需要的承载了创建Request
的工厂对象:
final class RequestFactory {
// 每个Service的方法
private final Method method;
// base url
private final HttpUrl baseUrl;
// http方法 get post
final String httpMethod;
// 相对url
private final @Nullable String relativeUrl;
// headers
private final @Nullable Headers headers;
// contentType
private final @Nullable MediaType contentType;
// 是否有body
private final boolean hasBody;
// 是否是FormEncoded请求
private final boolean isFormEncoded;
// 是否是Multipart请求
private final boolean isMultipart;
// 每个参数上的注解对应的Handler
private final ParameterHandler<?>[] parameterHandlers;
final boolean isKotlinSuspendFunction;
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;
}
}
得到了代表创建请求的RequestFactory
(请求工厂)之后,在后续的流程里,会使用工厂创建请求,本着用到再说的规则,在创建请求时,继续梳理RequestFactory
的相关代码。
先回顾一下到此为止,针对一个如下的Service:
public interface BaiduApi {
@GET("/")
Call<String> get1(@Query("aaa") String args);
}
我们做了哪些解析?
1)方法上的注解解析。得到了请求的相对路径、请求方式等等
2)方法参数的注解、参数解析。得到了该请求所需要的参数信息以及如何将Java方法参数转换为Http请求的处理类
以上两部分信息都被包装在了RequestFactory
中。
那么,剩余未处理的也就明朗起来了:方法返回值的解析
接下来围绕着这个目标,来深入到HttpServiceMethod#parseAnnotations。
2.3.4 HttpServiceMethod#parseAnnotations
在ServiceMethod
方法内部,调用RequestFactory#parseAnnotations
之后,得到代表创建请求的RequestFactory
,随后转到了HttpServiceMethod#parseAnnotations
进行剩余的注解解析处理。
由于上面已经贴过HttpServiceMethod#parseAnnotations
的代码,所以这里就个代码骨架,移除一些判断以及kotlin的支持:
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
// 获取方法的注解
Annotation[] annotations = method.getAnnotations();
// 定义adapter的类型
Type adapterType = method.getGenericReturnType();
// 获取CallAdapter
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
// CallAdapter的responseType
Type responseType = callAdapter.responseType();
// 获取responseConverter
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
// 返回一个CallAdapted实例
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
可以看到,整个流程的核心思路分为三步:1)获取CallAdapter
;2)获取responseConverter
;3:创建CallAdapted
实例。接下来先简单讲一下三个组件的获取方式,下一章详细讲解三个组件的职责。
2.3.4.1 HttpServiceMethod#createCallAdapter
关于CallAdapter
的详细定义,可以查看下面的章节,这里先简单的梳理一下获取的流程
首先第一步是获取CallAdapter
,通过查看代码:
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
try {
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) {
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
可以得知,内部跳转到了Retrofit.callAdapter
,而Retrofit.callAdapter
会跳转到Retrofit#nextCallAdapter
:
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++) {
// 迭代创建Retrofit时设置的AdapterFactory 找到匹配的第一个adapter
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
// 无法找到适配当前方法返回值的CallAdapter 抛异常
}
在这个阶段,Retrofit
会根据Service
的方法的返回类型,迭代所有的AdapterFactory
,调用对应的get
方法。
有了Adapter
之后,就明确了Adapter
能够处理的responseType
,就可以通过responseType
来获取对应的ResponseConvert
。
2.3.4.1 HttpServiceMethod#createResponseConverter
查看获取代码:
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations();
try {
// 跳到了Retrofit#responseBodyConverter
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) {
throw methodError(method, e, "Unable to create converter for %s", responseType);
}
}
代码内部跳到了Retrofit#responseBodyConverter
,最终会依赖于Retrofit#nextResponseBodyConverter
:
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
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;
}
}
// 未找到 抛异常
}
具体的获取类型同CallAdpater
差不多,根据responseType
,迭代所有的converterFactory
找到合适的进行返回。
有了CallAdapter
(适配Service
返回对象)、ResponseConvert
(适配Service
返回的业务对象),之后,就是进行整合。而CallAdapted
就是起到组合、调用适配的功能。所以最后一步,就是创建一个CallAdapted
:
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
至此,整个初始化流程就结束了,回到2.3.1,拿到CallAdapted
(ServiceMethod
的子类)放入缓存,接下来进入到真正的invoke
阶段。