本文分析的源码基于
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