本文分析的源码基于
retrofit:2.9.0
。
前言
Retrofit
基于OkHttp
,网络请求的工作本质上是 OkHttp
完成,而 Retrofit
仅负责 网络请求接口的封装,它们的关系示意图如下:
基本使用
首先添加依赖
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
// Retrofit的Gson转换器
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
封装一个工具类
object ServiceCreator {
private const val BASE_URL = "https://api.github.com"
private val httpClient = OkHttpClient.Builder()
private val builder = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(httpClient.build())
.addConverterFactory(GsonConverterFactory.create())
private val retrofit = builder.build()
fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)
}
写一个Retrofit
的接口
interface IUser {
@GET("/users/{nickname}")
fun getUser(@Path("nickname") nickname: String): Call<User>
}
@GET
中所填写的value
和BaseUrl
组成完整的路径,BaseUrl
在构造Retrofit
对象时已给出。
其中User
类如下
data class User(var id: Long? = null, var name: String? = null)
网络请求代码如下
val netRequestBn: Button = findViewById(R.id.net_request)
netRequestBn.setOnClickListener {
val iUser = ServiceCreator.create(IUser::class.java)
iUser.getUser("giagor").enqueue(object : Callback<User> {
override fun onResponse(call: Call<User>, response: Response<User>) {
val user = response.body()
Log.d(TAG, "$user")
}
override fun onFailure(call: Call<User>, t: Throwable) {
Log.d(TAG, "网络请求失败")
}
})
}
进行网络请求后,我们可以看到下面的日志信息
D/MainActivity: User(id=57672520, name=Giagor)
上面展示了异步请求的方式。如果想要进行同步请求,则需要调用iUser.getUser("giagor").execute()
,同步请求的情况下,要记得自己处理异常,比如使用try...catch
包住上面的...execute()
代码。
@Header
注解的使用:
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username)
Headers
不会互相覆盖,也就是有相同名字的Headers
会一并被包含到请求中。也可以给方法的参数使用@Header
注解,达到动态设置的目的,如下
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
如果authorization
为null
,@Header("Authorization")
注解会被忽略,并不会被提交,否则会调用authorization
的toString
方法作为@Header("Authorization")
的值。
对于复杂的Header
组合,也可以使用Map
:
@GET("user")
Call<User> getUser(@HeaderMap Map<String, String> headers)
如果有的Header
需要添加到每个请求上面,就使用OkHttp
的拦截器添加。
更多使用参考:
Retrofit对象创建
Retrofit
采用Builder
模式构建,其中Retrofit
的变量定义和构造方法如下:
public final class Retrofit {
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
// 网络请求的工厂,作用是产生网络的请求器(Call)
final okhttp3.Call.Factory callFactory;
// 网络请求的BaseUrl
final HttpUrl baseUrl;
// 数据转换器工厂的集合
final List<Converter.Factory> converterFactories;
// 网络请求适配器工厂的集合
final List<CallAdapter.Factory> callAdapterFactories;
// 回调方法执行器
final @Nullable Executor callbackExecutor;
// 是否提前对业务接口中的注解进行验证转换的标志位
final boolean validateEagerly;
Retrofit(
okhttp3.Call.Factory callFactory,
HttpUrl baseUrl,
List<Converter.Factory> converterFactories,
List<CallAdapter.Factory> callAdapterFactories,
@Nullable Executor callbackExecutor,
boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
...
}
看下Retrofit.Builder
:
public static final class Builder {
...
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
...
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);
}
}
Builder
构造方法:
- 需要有一个
Platform
参数,表示当前的平台,这里当然是Android
平台。
build
方法:
-
baseUrl
必须指定,否则抛异常。 -
如果没有指定
callFactory
,则默认为OkHttpClient
;如果需要对OkHttpClient
进行详细的设置,就需要自己构建并传入OkHttpClient
对象。 -
如果没有指定
callbackExecutor
,就获取platform
(Android
平台)的defaultCallbackExecutor
,最终获取到的是一个MainThreadExecutor
,它里面有一个主线程的Handler
,调用MainThreadExecutor
的execute
就可以使用Handler
向主线程post
一个任务。 -
接着会构建
callAdapterFactories
,其中的CallAdapter.Factory
主要用于对retrofit.Call
对象进行转化,其中的优先级顺序为:- 外界传入的callAdapterFactories
- platform.defaultCallAdapterFactories(…)
后面介绍CallAdapter的时候会再进行一些讲解
-
接着构建
converterFactories
,其中的Converter.Factory
主要用于转化数据,例如将返回的ResponseBody
转化为对象等。其中的优先级顺序:- BuiltInConverters
- 外界传入的converterFactories
- platform.defaultConverterFactories()
后面介绍Converter的时候会再进行一些讲解
接口实例的创建
我们在使用Retrofit
进行网络请求的时候,需要先定义一个接口,然后调用retrofit.create(serviceClass)
生成接口的一个实例,例如在「基本使用」的例子里,就是通过这种方式生成了一个IUser
实例,那么这是如何做到的呢?答案是动态代理。
动态代理的例子
我们先通过一个例子,简单地了解一下动态代理:
我们先定义一个注解
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class TIP(val value : String = "")
在定义一个接口
interface IMath {
@TIP("加法运算")
fun add(num1 : Int,num2 : Int) : Int
}
动态代理的实现:
val proxyBn: Button = findViewById(R.id.proxy_test)
proxyBn.setOnClickListener {
val iMath: IMath = Proxy.newProxyInstance(
IMath::class.java.classLoader,
arrayOf(IMath::class.java),
object : InvocationHandler {
override fun invoke(proxy: Any?, method: Method, args: Array<out Any>): Any {
val num1: Int = args[0] as Int
val num2: Int = args[1] as Int
Log.d(TAG, "方法名字: ${method.name}")
Log.d(TAG, "方法参数: num1为$num1,num2为$num2")
val tip: TIP? = method.getAnnotation(TIP::class.java)
tip?.let {
Log.d(TAG, "注解的值: ${it.value}")
}
return num1 + num2
}
}) as IMath
Log.d(TAG, "调用结果: ${iMath.add(2, 3)}")
}
打印的输出信息为:
D/MainActivity: 方法名字: add
D/MainActivity: 方法参数: num1为2,num2为3
D/MainActivity: 注解的值: 加法运算
D/MainActivity: 调用结果: 5
我们调用实例iMath
的方法,实际会调用到InvocationHandler
的invoke
方法,在该方法可以拿到方法名字、参数、注解等,从而实现代理的功能。
Retrofit::create
Retrofit::create
方法如下:
public <T> T create(final Class<T> service) {
// 对 Service 的接口进行检测
validateServiceInterface(service);
// 创建了网络请求接口的动态代理对象,即通过动态代理创建网络请求接口的实例并返回
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
// 如果调用的方法是Object类中的,则正常调用Object类中的方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 方法参数
args = args != null ? args : emptyArgs;
// 如果method是java8接口的default方法,则直接执行。否则会通过loadServiceMethod
// 方法获取一个ServiceMethod对象,然后调用它的invoke方法。
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
该方法主要做了两件事情:
- 调用
validateServiceInterface
方法对 Service 的接口进行检测。 - 创建并返回一个代理对象。在
InvocationHandler
的invoke
方法里面,调用了loadServiceMethod
方法获取一个ServiceMethod
对象,一个ServiceMethod
对象就代表网络请求接口里的一个方法,例如它可以代表我们IUser
里的getUser
请求方法,获取到ServiceMethod
后,就调用它的invoke
方法进行网络请求。
Retrofit::validateServiceInterface
:
private void validateServiceInterface(Class<?> service) {
// 若service不是接口,则抛出异常
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
// 判断service接口及其继承的所有接口是否包含了泛型参数,若包含则抛出异常
// 例如这样的接口会抛出异常:interface IUser<T,E> {...}
Deque<Class<?>> check = new ArrayDeque<>(1);
// 将service添加到双端队列中
check.add(service);
while (!check.isEmpty()) {
// 取出队列的第一个元素
Class<?> candidate = check.removeFirst();
// 不合法则抛出异常
if (candidate.getTypeParameters().length != 0) {
StringBuilder message =
new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
if (candidate != service) {
message.append(" which is an interface of ").append(service.getName());
}
throw new IllegalArgumentException(message.toString());
}
// 将candidate继承的接口全添加到双端队列中
Collections.addAll(check, candidate.getInterfaces());
}
// 是否急切地对Service接口的方法进行处理,该值默认为false,可以在Retrofit.Builder中设置
if (validateEagerly) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
// method不是default方法,并且不是static修饰的,则使用loadServiceMethod加载该方法
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
}
}
该方法会对service
进行检测,主要做了下面几件事情:
- 若service不是接口,则抛出异常
- 判断service接口及其继承的所有接口是否包含了泛型参数,若包含则抛出异常
- 若validateEagerly为true,则提前对service声明的所有方法提前进行检测,也就是对service每个声明的方法都调用loadServiceMethod方法进行加载,loadServiceMethod会加载出ServiceMethod并进行缓存(缓存的目的是为了复用),调用loadServiceMethod加载方法的时候,因为使用了反射所以会有一定的性能损耗。一般情况下是业务层调用到接口的某个方法(第一次调用该方法),才会使用loadServiceMethod进行相应的ServiceMethod的加载,这样的加载在时间上相对分散,因此此时的性能损耗不会很明显。而validateEagerly为true时对ServiceMethod的集中加载,性能损耗会比较明显,但是这样就可以尽早地检测开发者写的接口方法是否有问题,写的有问题会报错,这样可以尽早发现存在的问题,因此「validateEagerly为true」更多的是用在测试的时候。
代理对象的执行
获取ServiceMethod
我们查看Retrofit::loadServiceMethod
:
ServiceMethod<?> loadServiceMethod(Method method) {
// 判断是否有method对应的ServiceMethod对象,有则直接返回
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
// 利用serviceMethodCache加锁同步
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
// 创建一个ServiceMethod对象并将其加入缓存中
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
// 返回ServiceMethod对象
return result;
}
serviceMethodCache
是一个ConcurrentHashMap
实例,ConcurrentHashMap
是线程安全的HashMap
。这里先从serviceMethodCache
查看method
是否有对应的ServiceMethod
,有则直接返回,没有则调用ServiceMethod.parseAnnotations
方法对method
的注解进行处理,并将得到的ServiceMethod
对象加入到ServiceMethodCache
里面。
我们从中看出了Retrofit
的缓存思想:serviceMethodCache
是一个缓存,我们在调用Retrofit::create
方法的时候传入的是一个class
对象,而class
对象在进程内是单例的,所以获取到它的同一个Method
也是单例的,这里将Method
作为ConcurrentHashMap
的Key
,从而实现了对ServiceMethod
的缓存与复用。
ServiceMethod的构建
我们查看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
的parseAnnotations
方法就为我们构建了一个ServiceMethod
,主要分为下面两步:
- 调用
RequestFactory.parseAnnotations
方法创建RequestFactory
,这里主要是获取注解信息并且解析注解。 - 调用
HttpServiceMethod.parseAnnotations
方法(传入前面获取的requestFactory
),继续进行注解的解析,最终获取并返回一个HttpServiceMethod
对象。
创建RequestFactory
获取注解信息
RequestFactory::parseAnnotations
是一个静态方法
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
这是一个建造者模式。它将method
传入RequestFactory.Builder
,再调用Builder
的build
方法创建了一个RequestFactory
对象。
查看RequestFactory::Builder
的构造方法:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
// 方法注解
this.methodAnnotations = method.getAnnotations();
// 方法参数类型(带泛型)
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
Builder
中通过反射获取了方法的注解、方法参数类型(带泛型)、方法参数的注解。
小插曲:一些实验
Method::getParameterTypes
和Method::getGenericParameterTypes
有什么区别?这里我做了个实验,对于下面的这个类
public class Test {
public Long test(List<String> strs, List<Integer> nums,float num) {
return 0L;
}
...
}
如果我们使用getParameterTypes
方法:
Test test = new Test();
Class<?> testClass = test.getClass();
Method testMethod = testClass.getMethod("test", List.class, List.class, float.class);
System.out.println(testMethod.getName());
System.out.println(Arrays.toString(testMethod.getParameterTypes()));
输出如下:
test
[interface java.util.List, interface java.util.List, float]
如果我们使用getGenericParameterTypes
方法:
Test test = new Test();
Class<?> testClass = test.getClass();
Method testMethod = testClass.getMethod("test", List.class, List.class,float.class);
System.out.println(testMethod.getName());
System.out.println(Arrays.toString(testMethod.getGenericParameterTypes()));
输出如下:
test
[java.util.List<java.lang.String>, java.util.List<java.lang.Integer>, float]
可以看出它们的区别是getGenericParameterTypes
获取方法参数类型的时候会带上泛型,而getParameterTypes
不会带上泛型。
另外,Method::getParameterAnnotations
也有需要注意的点,我们先定义两个注解
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno1 {
}
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno2 {
}
然后将Test::test
的方法参数使用注解修饰
public class Test {
public Long test(@Anno1 @Anno2 List<String> strs, @Anno2 List<Integer> nums,
float num) {
return 0L;
}
}
通过getParameterAnnotations
方法去获取test
方法参数的注解
Test test = new Test();
Class<?> testClass = test.getClass();
Method testMethod = testClass.getMethod("test", List.class, List.class, float.class);
System.out.println(testMethod.getName());
Annotation[][] paramAnnotations = testMethod.getParameterAnnotations();
for (Annotation[] paramAnnotation : paramAnnotations) {
for (Annotation annotation : paramAnnotation) {
System.out.print(annotation.toString() + " ");
}
System.out.println();
}
输出信息:
test
@Anno1() @Anno2()
@Anno2()
注意,这里之所以可以获取到Anno1
和Anno2
,是因为这两个注解的存活期到RetentionPolicy.RUNTIME
,如果Anno1
和Anno2
的存活期到RetentionPolicy.CLASS
或RetentionPolicy.SOURCE
,那么在这里将获取不到Anno1
、Anno2
注解,因为反射是在运行期执行的。
另外,paramAnnotations
是二维数组,方法有多少个参数,二维数组的大小就是多少,其中的每个一维数组分别对应着每个参数上的注解。
注解解析
再查看RequestFactory.Builder
的build
方法
RequestFactory build() {
// 遍历方法的注解,对每个注解进行解析
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...// 一些异常处理
// 方法参数的个数
int parameterCount = parameterAnnotationsArray.length;
// 每个参数都创建一个ParameterHandler
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
...// 一些异常处理
return new RequestFactory(this);
}
在build
方法做了三件事情:
- 对方法的每个注解调用
parseMethodAnnotation
方法进行解析 - 对方法的每个参数调用了
parseParameter
解析,生成ParameterHandler
对象 - 根据
Builder
创建并返回RequestFactory
对象
方法注解的解析
RequestFactory.Builder::parseMethodAnnotation
方法:
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
这里对方法注解的处理方式主要可以分为三类:
GET
、POST
等请求方法:调用RequestFactory.Builder::parseHttpMethodAndPath
方法进行处理Headers
的注解:调用RequestFactory.Builder::parseHeaders
方法进行处理Multipart
、FormUrlEncoded
注解:主要是在标记变量中进行记录
我们看下第1
和2
步是如何处理的。
对GET
、POST
等请求方法的注解解析,使用RequestFactory.Builder::parseHttpMethodAndPath
:
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
// 1.若已设置过httpMethod,则抛出异常
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;
// 若请求方法的注解(如GET)里面没有写值,则结束
if (value.isEmpty()) {
return;
}
// Get the relative URL path and existing query string, if present.
// 2.判断请求方法的注解中的值是否合理,不合理则抛出异常
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);
}
}
// 3.记录相对Url;解析并记录注解中的占位符(parsePathParameters方法内部使用了正则表达式)
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
该方法主要做了下面的几件事情:
- 记录 请求方法 及 是否有请求体
- 判断请求方法的注解中的值是否合理,不合理则抛出异常
- 记录相对Url,解析并记录注解中的占位符
我们以GET
请求方法注解为例,第2
步主要是防止GET
的出现类似"users?sortby={sortby}"
这种值,它希望我们动态设置的参数使用@Query
注解来实现,举一个例子:
@GET("/banner")
fun getBanners(@Query("type") type: Int): Call<BannerJson>
而不是
@GET("/banner?type={type}")
fun getBanners(@Path("type") type: Int): Call<BannerJson>
第3
步,例如我们的请求方法为
interface IUser {
@GET("/users/{nickname}")
fun getUser(@Path("nickname") nickname: String): Call<User>
}
那么计算后的值为
// 相对url
this.relativeUrl = "/users/{nickname}"
// 也就是{}包裹的值,如果有多个{},那么Set<String>会有多个值
this.relativeUrlParamNames = 包含"nickname"的Set<String>
对Headers
注解的解析,使用RequestFactory.Builder::parseHeaders
方法:
private Headers parseHeaders(String[] headers) {
// 这是okhttp3的Headers.Builder
Headers.Builder builder = new Headers.Builder();
// 遍历传入的headers
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);
}
// 获取Header名和Header值
String headerName = header.substring(0, colon);
String headerValue = header.substring(colon + 1).trim();
// 如果Header是"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 {
// 将Header添加到builder中
builder.add(headerName, headerValue);
}
}
// 返回okhttp3.Headers
return builder.build();
}
该方法主要做的事情:将传入的字符串数组headers
,构造为okhttp3.Headers
并返回,对于Content-Type
类型的Header
,会进行一些特殊的处理。
对方法参数的处理
RequestFactory.Builder::parseParameter
:
# p:方法参数的位置
# parameterType:方法参数的类型(带泛型)
# annotations:方法参数的注解
# allowContinuation:是否允许为Continuation(通过是否为最后一个参数进行判断)
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
// 对该参数的每个注解进行解析
for (Annotation annotation : annotations) {
// 使用parseParameterAnnotation进行注解的解析
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
// 一个方法参数最多只能有一个Retrofit注解,多了则抛异常
if (result != null) {
throw parameterError(
method, p, "Multiple Retrofit annotations found, only one allowed.");
}
// 记录结果
result = annotationAction;
}
}
if (result == null) {
// 对kotlin协程方面的特殊处理
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
解析方法参数的注解,且一个方法参数最多只能有一个Retrofit
注解。最终返回result
。 - 若参数是方法的最后一个参数且为
Continuation
类型,说明与kotlin
协程有关,做特殊处理。最终返回null
。
parseParameterAnnotation
方法会对参数每种类型的注解进行特有的处理,然后返回相应的ParameterHandler
。
ServiceMethod 的创建
ServiceMethod
的创建使用HttpServiceMethod.parseAnnotations
方法:
// 检查接口方法的注释,以构造一个使用HTTP的可重用的ServiceMethod。这可能需要代价高昂的反射,所以
// 对于要使用到的ServiceMethod最好只构建一次然后重用它
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
// 记录是否为suspend函数
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
// 获取方法注解
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType =
Utils.getParameterLowerBound(
0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
// 记录方法的返回类型(含泛型信息),如Call<User>
adapterType = method.getGenericReturnType();
}
// 创建CallAdapter对象
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
// 接口方法的实际返回类型,例如Call<User>会返回User
Type responseType = callAdapter.responseType();
...(一些异常处理)
// 创建Converter对象
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
// 不是suspend函数,就创建并返回一个CallAdapted对象
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
这里暂时先不考虑Retrofit
对协程的支持。这个方法主要做了下面几件事:
- 记录方法的返回类型(含泛型信息),如
Call<User>
- 创建
CallAdapter
对象 - 创建
Converter
对象 - 创建并返回一个
CallAdapted
对象,CallAdapted
继承至HttpServiceMethod
CallAdapter
CallAdapter
用于将retrofit2.Call<R>
对象适配为类型为T
的对象,定义如下:
// CallAdapter实例由CallAdapter.Factory创建,Retrofit里面有CallAdapter.Factory的实例
public interface CallAdapter<R, T> {
// 返回Response Type,如Call<User>的Response Type就是User
Type responseType();
// 适配:Call<R> -> T
T adapt(Call<R> call);
// 基于接口方法的返回类型,创建CallAdapter实例
abstract class Factory {
// 如果该工厂可以处理指定的returnType和annotations的接口方法,则返回CallAdapter,否则返回null
// returnType:接口方法的返回类型,如Call<User>
public abstract @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit);
// 提取泛型参数的上界,例如index = 1,type = Map<String, ? extends Runnable>,则
// 返回值为Runnable
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
// 返回Type的raw class type,例如type = List<? extends Runnable>,则返回List.class
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
查看HttpServiceMethod::createCallAdapter
方法,看CallAdapter
是如何被创建的:
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
try {
//noinspection unchecked
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
Retrofit::callAdapter
:
// 从可用的factories中返回returnType相应的CallAdapter
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
Retrofit::nextCallAdapter
:
# skipPast:null
# returnType:接口方法的返回类型,如Call<User>
# annotations:接口方法的注解
public CallAdapter<?, ?> nextCallAdapter(
@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
Objects.requireNonNull(returnType, "returnType == null");
Objects.requireNonNull(annotations, "annotations == null");
// 从列表开始寻找的位置,这里是从0开始
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
// 若索引处的CallAdapter.Factory可以处理该接口方法,则返回CallAdapter,否则返回null
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
// 可以获取到CallAdapter则返回它
if (adapter != null) {
return adapter;
}
}
// 没有获取到适合该接口方法的CallAdapter,则拼接异常信息并抛出异常
StringBuilder builder = ...
...
throw new IllegalArgumentException(builder.toString());
}
该方法会遍历Retrofit
的callAdapterFactories
,查看是否有可以处理指定的returnType
和annotations
的CallAdapter.Factory
,有则返回该CallAdapter
,整个列表都没有找到合适的CallAdapter.Factory
,则抛出异常。
回到Retrofit.Builder::build
方法,可以知道callAdapterFactories
中有哪些元素
List<CallAdapter.Factory> callAdapterFactories =
new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
Platform
的defaultCallAdapterFactories
如下:
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
在「Retrofit对象创建」当中提到,Platform
的实例是Android
,Android
实例通过SDK
版本是否大于等于24
来判断hasJava8Types
的值是否为true
,我们这里认为它是true
。因为hasJava8Types
的值为true
,所以在defaultCallAdapterFactories
方法会将CompletableFutureCallAdapterFactory
和DefaultCallAdapterFactory
添加到callAdapterFactories
中,所以callAdapterFactories
的元素:
- 用户自定义的CallAdapter.Factory(我们一般不会自定义CallAdapter.Factory)
- CompletableFutureCallAdapterFactory(只处理接口方法的返回类型为
CompletableFuture<T>
的) - DefaultCallAdapterFactory
RxJava的适配器:
XXX.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
,就是属于一种「用户自定义的CallAdapter.Factory」。
并且由上至下优先级递减,其中DefaultCallAdapterFactory
的优先级最低。一般情况下,由DefaultCallAdapterFactory
处理我们的请求,这里直接分析它即可:
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
// 默认情况下,这是一个MainThreadExecutor,可以通过handler将任务调度到主线程中执行
private final @Nullable Executor callbackExecutor;
DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
# returnType:接口方法的返回类型,如Call<User>
# annotations:接口方法的注解
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 检查接口方法的返回类型
if (getRawType(returnType) != Call.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
}
// 获取返回类型的泛型参数的上界
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
// 判断方法注解是否包含SkipCallbackExecutor.class,一般不包含,所以这里executor的值为
// callbackExecutor(默认情况下,它是一个MainThreadExecutor)
final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
// 创建并返回CallAdapter
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
// 将Call<Object>适配为Call<Object>
@Override
public Call<Object> adapt(Call<Object> call) {
// 正常情况下executor不为null,因此call会被适配为一个ExecutorCallbackCall
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {...}
}
简单来说,DefaultCallAdapterFactory
的get
方法会返回一个CallAdapter
,通过CallAdapter
的adapt
方法可以将传入的retrofit2.Call
适配包装为一个ExecutorCallbackCall
。
这个ExecutorCallbackCall
实际上就是我们业务层拿到的retrofit2.Call
,可以调用它的enqueue
或者execute
方法进行网络请求,ExecutorCallbackCall
是DefaultCallAdapterFactory
的静态内部类,其定义如下:
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
// retrofit2.Call
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
# callback:业务层传入的Callback
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
// 调用delegate的enqueue进行请求
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
// 将回调给业务层的代码,切到主线程中执行
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on
// cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
// 将回调给业务层的代码,切到主线程中执行
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
...
@Override
public Response<T> execute() throws IOException {
return delegate.execute();
}
...
}
两种执行方式:
- enqueue:异步执行。使用
callbackExecutor
将给业务层的回调代码切换到主线程中执行。 - execute:同步执行。
实际上,
callbackExecutor
也不一定是切换到主线程的MainThreadExecutor
,但是默认情况下是MainThreadExecutor
,这里我们就认为它是MainThreadExecutor
,展开讨论。
ExecutorCallbackCall
声明的其余方法不多介绍:
那么,传入ExecutorCallbackCall
的delegate
变量是怎样的呢?后面将会介绍。
后面我们会知道
delegate
变量其实是一个OkHttpCall
实例。
Converter
Converter
是一个接口,用于将类型为F
的数据转换为类型T
:
// Converter实例由Converter.Factory创建,Retrofit里面有Converter.Factory的实例
public interface Converter<F, T> {
@Nullable
T convert(F value) throws IOException;
abstract class Factory {
// 该Factory可以处理type和annotations的接口方法,则返回Converter,否则返回null
# type:接口方法的实际返回类型,例如接口方法声明的是Call<User>类型,则这里传入的是User类型
# annotations:接口方法的注解
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
public @Nullable Converter<?, RequestBody> requestBodyConverter(
Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations,
Retrofit retrofit) {
return null;
}
public @Nullable Converter<?, String> stringConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
Converter.Factory
的几个方法:
- responseBodyConverter:完成
ResponseBody
到实际的返回类型的转化,实际返回类型例如是Call<User>
里面的泛型User
。 - requestBodyConverter:完成对象到
RequestBody
的构造。
关于Converter.Factory
更多信息,可以查看 Retrofit2 完全解析 探索与okhttp之间的关系_Hongyang-CSDN博客 的 「六、自定义Converter.Factory」 一节。
查看HttpServiceMethod::createResponseConverter
如何创建Converter
:
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create converter for %s", responseType);
}
}
Retrofit::responseBodyConverter
:
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
Retrofit::nextResponseBodyConverter
:
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
Objects.requireNonNull(type, "type == null");
Objects.requireNonNull(annotations, "annotations == null");
// 从列表开始寻找的位置,这里是从0开始
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
// 若索引处的Converter.Factory可以处理接口方法,则返回Converter,否则返回null
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
// 可以获取到Converter则返回它
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
// 没有获取到适合该接口方法的Converter,则拼接异常信息并抛出异常
StringBuilder builder = ...
...
throw new IllegalArgumentException(builder.toString());
}
获取Converter
和获取CallAdapter
的过程非常类似。
从Retrofit.Builder::build
得知,列表中会有三种类型的Converter.Factory
:
- BuiltInConverters
- 用户自定义的Converter.Factory,如GsonConverterFactory
- platform.defaultConverterFactories,其实就是OptionalConverterFactory
BuiltInConverters:当接口方法声明的是Call<ResponseBody>
、Call<Void>
、Call<Unit>
的时候,BuiltInConverters
可以处理,并返回相应的Converter
。
OptionalConverterFactory:从该类的responseBodyConverter
方法可以看出,该类与Optional
类有关,若我们的接口方法的返回值没有用到Optional
类,则OptionalConverterFactory
会返回null
。
另外要说明的是,BuiltInConverters
是优先级最高的Converter.Factory
,这防止其它工厂覆盖它的行为;而OptionalConverterFactory
的优先级比自定义工厂的优先级低,是优先级最低的Converter.Factory
。
CallAdapted
在不考虑Retrofit
协程支持的情况下,HttpServiceMethod::parseAnnotations
最终会创建并返回一个CallAdapted
对象,CallAdapted
的继承关系:
CallAdapted -> HttpServiceMethod -> ServiceMethod
CallAdapted
是HttpServiceMethod
的静态内部类
ServiceMethod
是一个抽象类,定义如下:
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {...}
// 抽象方法invoke
abstract @Nullable T invoke(Object[] args);
}
它内部定义了抽象方法invoke
,在Retrofit::create
动态代理InvocationHandler
中,就调用了ServiceMethod
的invoke
方法。
ServiceMethod
的直接子类只有一个,即HttpServiceMethod
,它也是一个抽象类:
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
...
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {...}
...
}
HttpServiceMethod
的大部分方法前面都已经看过了(即省略号的部分)。上面列出的代码,主要关注的点:
- 在
invoke
方法中,创建了一个retrofit2.OkHttpCall
对象,并且调用虚方法adapt
对OkHttpCall
进行转化,adapt
方法在子类中实现。 CallAdapted
继承至HttpServiceMethod
。
注意,HttpServiceMethod
重写了父类的invoke
方法并标记为final
,意味着子类无法重写该方法,又由于ServiceMethod
的直接子类只有HttpServiceMethod
一个,所以调用ServiceMethod::invoke
,实际上调用的是HttpServiceMethod::invoke
。
CallAdapted
定义如下:
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
在HttpServiceMethod::parseAnnotations
中创建CallAdapted
对象的语句是:
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
CallAdapted
类中存在很多泛型参数,这里在一个假定的场景下进行讨论,方便理解,假如接口方法的返回类型是Call<User>
,并且使用的CallAdapter.Factory
是DefaultCallAdapterFactory
,则CallAdapted
类中的泛型参数为:
ResponseT = Object;
ReturnT = Call<User>;
即CallAdapted<Object, Call<User>>
因此,CallAdapted
的adapt
方法就可以实现转化:retrofit2.Call -> retrofit2.Call。
关系梳理
我们业务代码中通过retrofit.create
可以拿到一个接口如IUser
,该接口是一个代理对象,调用IUser::getUser
方法希望获取一个retrofit2.Call<User>
,实际会调用到代理对象InvocationHandler
的invoke
方法中,接着会调用loadServiceMethod(method).invoke(args)
,在不考虑缓存命中的情况下,loadServiceMethod(method)
会获取到一个CallAdapted
对象,接着调用CallAdapted
的invoke
方法,实际会执行父类HttpServiceMethod::invoke
,里面会创建一个retrofit2.OkHttpCall<Object>
对象,然后调用子类CallAdapted
的adapt
方法,将该OkHttpCall
转化为retrofit2.Call<User>
。
CallAdapted::adapt
内部依靠CallAdapter::adapt
完成对象转化,该CallAdapter
来源于DefaultCallAdapterFactory::get
,返回的CallAdapter
如下:
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
所以,CallAdapted::adapt
内部的转化实际是:retrofit2.OkHttpCall<Object>
-> ExecutorCallbackCall<User>
。所以,业务层调用IUser::getUser
方法拿到的实际是ExecutorCallbackCall<User>
(ExecutorCallbackCall
继承至retrofit2.Call
)。
前面介绍过,ExecutorCallbackCall
内部有一个类型为retrofit2.Call<User>
的delegate
代理,在异步请求方法enqueue
中,会调用delegate.enqueue
进行网络请求,然后将给业务层的回调切到主线程中执行;在同步请求方法execute
中,就是直接调用delegate
代理的execute
方法。而这个delegate
代理实际上就是在HttpServiceMethod::invoke
创建的retrofit2.OkHttpCall
对象。
一个简单的关系图:
retrofit2.Call
该接口定义了下面的方法:
public interface Call<T> extends Cloneable {
// 同步请求
Response<T> execute() throws IOException;
// 异步请求
void enqueue(Callback<T> callback);
boolean isExecuted();
void cancel();
boolean isCanceled();
Call<T> clone();
Request request();
Timeout timeout();
}
OkHttpCall
retrofit2.OkHttpCall
实现了retrofit2.Call
接口。
当业务层调用拿到的retrofit2.Call
(即ExecutorCallbackCall
)的enqueue
或者execute
方法时,都会调用到retrofit2.OkHttpCall
的enqueue
或者execute
方法。
enqueue
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
// 检测该OkHttpCall是否已经执行过,若执行过则抛出异常。
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
// 创建一个okhttp3.Call对象。
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
// 检测是否被取消。
if (canceled) {
call.cancel();
}
// 使用okhttp3.Call发起异步的okhttp网络请求
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
// 解析响应
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
// 回调响应
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
// 回调,通知失败
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
代码很长,逻辑很简单。该方法主要做了下面几件事情:
- 检测该OkHttpCall是否已经执行过,若执行过则抛出异常。
- 调用createRawCall方法创建一个okhttp3.Call对象。
- 检测是否被取消。
- 使用okhttp3.Call发起okhttp的网络请求,并传入okhttp3.Callback回调,这里就是真正进行网络请求的地方
- 请求成功:通过parseResponse方法解析响应,调用callback.onResponse方法进行回调,该callback由ExecutorCallbackCall::enqueue传入。
- 请求失败:调用callback.onFailure回调方法通知失败,该callback由ExecutorCallbackCall::enqueue传入。
execute
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
// 检测该OkHttpCall是否已经执行过,若执行过则抛出异常。
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
// 获取一个okhttp3.Call对象
call = getRawCall();
}
// 检测是否被取消
if (canceled) {
call.cancel();
}
// 使用okhttp3.Call发起同步的okhttp网络请求,并使用parseResponse方法解析响应
return parseResponse(call.execute());
}
该方法的逻辑也很简单:
- 检测该OkHttpCall是否已经执行过,若执行过则抛出异常。
- 获取一个okhttp3.Call对象。
- 检测是否被取消。
- 使用okhttp3.Call发起同步的okhttp网络请求,并使用parseResponse方法解析响应。
个人有一点疑问:
既然
OkHttpCall
通过executed
变量防止重复进行网络请求,那么对rawCall
还要这么多判断干啥呢?这个getRawCall
方法是不是有点多余?不可以直接使用createRawCall
方法去创建一个okhttp3.Call
对象吗?
okhttp3.Call 的 获取/创建
OkHttpCall
的enqueue
方法,使用createRawCall
创建一个okhttp3.Call
对象;OkHttpCall
的execute
方法使用getRawCall
获取/创建 一个okhttp3.Call
对象。
OkHttpCall::getRawCall
:
private okhttp3.Call getRawCall() throws IOException {
// 若之前已经创建了okhttp3.Call对象,则直接返回该对象
okhttp3.Call call = rawCall;
if (call != null) return call;
// Re-throw previous failures if this isn't the first attempt.
// 若这不是第一次创建okhttp3.Call,并且之前创建的时候抛出异常,则这里重抛异常
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else if (creationFailure instanceof RuntimeException) {
throw (RuntimeException) creationFailure;
} else {
throw (Error) creationFailure;
}
}
// Create and remember either the success or the failure.
// 创建okhttp3.Call对象,若有异常则记录
try {
return rawCall = createRawCall();
} catch (RuntimeException | Error | IOException e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
可以看出,最终还是要调用createRawCall
方法创建一个okhttp3.Call
对象,OkHttpCall::createRawCall
方法:
private okhttp3.Call createRawCall() throws IOException {
// 创建okhttp3.Call对象
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
// 返回call对象
return call;
}
callFactory
的类型是okhttp3.Call.Factory
,来源于Retrofit
的成员变量,在Retrofit.Builder
的配置中,若开发者没有指定callFactory
,那么它默认是OkHttpClient()
。requestFactory
是在前面的ServiceMethod::parseAnnotations
中,通过RequestFactory.parseAnnotations
创建的,在创建的时候会对接口方法的相关信息进行解析,所以requestFactory
代表了接口方法的信息,它的create
方法可以创建一个okhttp3.Request
对象,便于我们使用okhttp
发起网络请求。
所以在createRawCall
方法中,默认是通过OkHttpClient
的newCall
方法创建一个okhttp3.Call
对象并返回。
parseResponse
parseResponse
用于将okhttp
响应转化为retrofit2
响应。假如我们的接口方法返回值为Call<User>
,那么parseResponse
职责就是将okhttp3.Response
转化为retrofit2.Response<User>
。
parseResponse
方法:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
// 替换原来响应中的ResponseBody
rawResponse =
rawResponse
.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
// 使用responseConverter.convert进行数据类型的转换
T body = responseConverter.convert(catchingBody);
// 返回响应
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
该方法的主要逻辑是使用responseConverter.convert
进行数据类型的转换,然后创建并返回retrofit2.Response
对象。其中responseConverter
的类型是Converter
(比如它可以是GsonResponseBodyConverter
),它是由Retrofit
的Converter.Factory
创建的,创建过程在前面的「Converter」一节中已经介绍过了。
对协程的支持
Retrofit
在2.6
版本开始对协程进行支持。
例子如下:
interface IUser {
@GET("/users/{nickname}")
suspend fun getUser(@Path("nickname") nickname: String): User
}
val iUser = ServiceCreator.create(IUser::class.java)
GlobalScope.launch(Dispatchers.Main) {
val user = iUser.getUser("giagor")
Log.d(TAG, "成功: $user")
}
注意两点:
- 接口方法使用
suspend
修饰。 - 接口方法的返回值由
Call<User>
改成User
。 - 开发者只需要调用
iUser.getUser
就可以进行网络请求,而不需要调用enqueue、execute
之类的方法。
接下来看下与协程支持相关的源码。
在「创建RequestFactory
」里,会走到RequestFactory.Builder
的build
方法:
RequestFactory build() {
...
// 方法参数的个数
int parameterCount = parameterAnnotationsArray.length;
// 每个参数都创建一个ParameterHandler
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
...// 一些异常处理
return new RequestFactory(this);
}
在对方法的每个参数进行解析的时候,会走到RequestFactory.Builder::parseParameter
方法:
# p:方法参数的位置
# parameterType:方法参数的类型(带泛型)
# annotations:方法参数的注解
# allowContinuation:是否允许为Continuation(通过是否为最后一个参数进行判断)
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
...
if (result == null) {
// 对kotlin协程方面的特殊处理
if (allowContinuation) {
try {
// 如果方法最后一个参数为Continuation,就将isKotlinSuspendFunction标记位
// 设置为true
if (Utils.getRawType(parameterType) == Continuation.class) {
isKotlinSuspendFunction = true;
return null;
}
} catch (NoClassDefFoundError ignored) {
}
}
throw parameterError(method, p, "No Retrofit annotation found.");
}
return result;
}
后面在「ServiceMethod
的创建」里,会根据isKotlinSuspendFunction
标记位进行些逻辑判断,并最终决定创建什么类型的ServiceMethod
:
// 检查接口方法的注释,以构造一个使用HTTP的可重用的ServiceMethod。这可能需要代价高昂的反射,所以
// 对于要使用到的ServiceMethod最好只构建一次然后重用它
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
// 记录是否为suspend函数
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
// 获取方法注解
Annotation[] annotations = method.getAnnotations();
Type adapterType;
// 如果是Kotlin的suspend方法
if (isKotlinSuspendFunction) {
// 获取方法参数类型(带泛型)
Type[] parameterTypes = method.getGenericParameterTypes();
// 获取 Continuation 的泛型参数,它就是 suspend 方法的返回值类型
Type responseType =
Utils.getParameterLowerBound(
0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
// 若Continuation 的泛型参数是Response,说明接口方法的返回值为Response,将
// continuationWantsResponse标记位设置为true
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
...
}
// 创建CallAdapter对象
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
// 接口方法的实际返回类型,例如Call<User>会返回User
Type responseType = callAdapter.responseType();
...(一些异常处理)
// 创建Converter对象
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
// 不是suspend函数,就创建并返回一个CallAdapted对象
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
// 是suspend函数,且接口方法的返回值为Response,则创建一个SuspendForResponse对象
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
// 是suspend函数,且接口方法的返回值不是Response,而是User之类的
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
该方法中,与协程相关的代码有以下几部分
- 如果接口方法是
suspend
方法,则获取Continuation
的泛型参数,从而知道suspend
方法的返回值类型。 - 如果
suspend
方法返回值为Response
,则将continuationWantsResponse
标记位设置为true
。 - 在
isKotlinSuspendFunction
为true
的前提下,根据suspend
方法需要的是Response
还是具体的类型,分别返回SuspendForResponse
和SuspendForBody
对象。
SuspendForResponse
SuspendForResponse
继承至HttpServiceMethod
并且是它的一个静态内部类:
static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
SuspendForResponse(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, Call<ResponseT>> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override
protected Object adapt(Call<ResponseT> call, Object[] args) {
// 得到的call是ExecutorCallbackCall
call = callAdapter.adapt(call);
// 获取接口方法的最后一个参数Continuation
//noinspection unchecked Checked by reflection inside RequestFactory.
Continuation<Response<ResponseT>> continuation =
(Continuation<Response<ResponseT>>) args[args.length - 1];
// 调用awaitResponse方法,注意call和continuation都作为参数传入
// See SuspendForBody for explanation about this try/catch.
try {
return KotlinExtensions.awaitResponse(call, continuation);
} catch (Exception e) {
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
}
awaitResponse
方法:
# 函数类型等价为:fun <T> awaitResponse(retrofit2.Call<T>,Continuation) : Response<T>
suspend fun <T> Call<T>.awaitResponse(): Response<T> {
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel()
}
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
// 直接将Response返回给业务层
continuation.resume(response)
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
可以看到,它使用suspendCancellableCoroutine
主动挂起当前的协程,然后使用ExecutorCallbackCall
的enqueue
进行网络请求,ExecutorCallbackCall
内部又调用到OkHttpCall
的enqueue
方法进行网络请求,最终会调用到okhttp3.Call
的enqueue
进行真正的网络请求。
在OkHttp
进行异步的网络请求的时候,协程是挂起状态,等网络请求结束后会通过续体Continuation
恢复协程,从而让协程中的代码可以继续往下执行。
SuspendForBody
SuspendForBody
也是HttpServiceMethod
的静态内部类并继承至它:
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
private final boolean isNullable;
SuspendForBody(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, Call<ResponseT>> callAdapter,
boolean isNullable) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
// 接口方法的返回值是否为「可空」的
this.isNullable = isNullable;
}
@Override
protected Object adapt(Call<ResponseT> call, Object[] args) {
// 得到的call是ExecutorCallbackCall
call = callAdapter.adapt(call);
// 获取接口方法的最后一个参数Continuation
//noinspection unchecked Checked by reflection inside RequestFactory.
Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
// Calls to OkHttp Call.enqueue() like those inside await and awaitNullable can sometimes
// invoke the supplied callback with an exception before the invoking stack frame can return.
// Coroutines will intercept the subsequent invocation of the Continuation and throw the
// exception synchronously. A Java Proxy cannot throw checked exceptions without them being
// declared on the interface method. To avoid the synchronous checked exception being wrapped
// in an UndeclaredThrowableException, it is intercepted and supplied to a helper which will
// force suspension to occur so that it can be instead delivered to the continuation to
// bypass this restriction.
try {
// 根据isNullable的值,调用相应的挂起函数
return isNullable
? KotlinExtensions.awaitNullable(call, continuation)
: KotlinExtensions.await(call, continuation);
} catch (Exception e) {
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
}
如果isNullable
为true
,则调用awaitNullable
方法:
@JvmName("awaitNullable")
suspend fun <T : Any> Call<T?>.await(): T? {
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel()
}
enqueue(object : Callback<T?> {
override fun onResponse(call: Call<T?>, response: Response<T?>) {
// 对Response做一些处理后,再返回给业务层
if (response.isSuccessful) {
continuation.resume(response.body())
} else {
continuation.resumeWithException(HttpException(response))
}
}
override fun onFailure(call: Call<T?>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
可以看到,它的处理过程和前面提到的awaitResponse
方法类似。唯一不同的地方在于awaitNullable
方法中会对response
做一些处理,通过判断response
是否为isSuccessful
,从而将body
或者异常返回给业务层。
再看看await
方法:
suspend fun <T : Any> Call<T>.await(): T {
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel()
}
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
val body = response.body()
if (body == null) {
val invocation = call.request().tag(Invocation::class.java)!!
val method = invocation.method()
val e = KotlinNullPointerException("Response from " +
method.declaringClass.name +
'.' +
method.name +
" was null but response body type was declared as non-null")
continuation.resumeWithException(e)
} else {
continuation.resume(body)
}
} else {
continuation.resumeWithException(HttpException(response))
}
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
它的处理过程和awaitNullable
方法类型,唯一区别在于await
方法中,还增加了一个response.body
是否为null
的判断,为null
则返回异常给业务层,不为null
则将body
正常地返回给业务层。
总结
总的调用流程图(不含对协程支持的部分):
请求方式:业务层通过iUser.getUser
拿到retrofit2.Call<User>
对象后
- 同步请求:调用
Call<User>::execute()
- 异步请求:调用
Call<User>::enqueue(...)
Retrofit
代码中基本很少涉及到对网络请求的处理,它更多的是对OkHttp
的封装,在 OkHttp
现有的 API 上提供了一套更便于使用的框架。
Retrofit
的注解是一种运行时注解,它通过动态代理对Service对象进行创建,通过反射对注解进行解析,这样虽然会有一定的性能损耗,但性能的损耗却带来了十分易用的 API。开发者的Service接口中,每个接口方法对应着一个ServiceMethod
对象。
另外,「运行时注解+反射」是一种常用的在运行时动态获取信息的手段。
Retrofit
创建Service对象时使用了动态代理,在返回代理对象之前,会先对 Service 的接口进行检测,若开发者将validateEagerly
设置为true
,则会提前解析该Service接口中的所有方法,为这些方法创建对应的ServiceMethod
对象,这种做法有利于尽早发现接口方法的书写错误,一般用于测试使用,将validateEagerly
设置为true
的缺点是,性能损耗表现得更集中、明显。默认validateEagerly
的值为false
,这样会在Service接口的方法调用时再创建对应的ServiceMethod
对象。Retrofit
通过serviceMethodCache
对已经创建的ServiceMethod
对象进行缓存,从而避免了重复解析带来的性能损耗。
在 HttpServiceMethod.parseAnnotations
方法中会完成 ServiceMethod
对象的创建,它在创建的过程中同时进行了接口对应的 CallAdapter
以及 Converter
的创建。
其中,CallAdapter
用于将Call<R>
对象适配为需要的类型 T
对象,也就是对 Call
进行转换。
而 Converter
则是用于将 F
类型的数据转换为 T
,往往是用于对 Response
的 body 进行转换。
对于 CallAdapter
和 Converter
都是通过它们对应的工厂类进行创建,创建时会根据工厂列表的顺序从前向后尝试进行创建,也就是说在工厂列表中越靠前的工厂其优先级越大。
Retrofit
的网络请求的执行依赖于 OkHttp
,它首先会通过 RequestFactory
进行 okhttp3.Request
的构造,RequestFactory
的信息由前面的注解解析中得来。之后会根据这个 Request
创建一个 okhttp3.Call
对象,在同步和异步请求时分别调用其对应的 execute
及 enqueue
方法。
Retrofit
在2.6
版本开始对协程进行支持,所谓对协程的支持,其实就是在进行网络异步请求的时候,将协程主动地进行挂起,等到异步请求完成后(请求成功或请求失败),这时再通过续体Continuation
恢复协程,让协程的后续代码可以继续执行。