简介
Retrofit turns your HTTP API into a Java interface.
Retrofit将HTTP API转换为Java接口
本文基于Retrofit
2.9.0版本源码分析!
依赖添加:
com.squareup.retrofit2:retrofit:2.9.0
使用
我们在这以官网的Demo为例,来看下最简单的使用:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
} ①
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build(); ②
GitHubService service = retrofit.create(GitHubService.class); ③
Call<List<Repo>> repos = service.listRepos("octocat"); ④
repos.enqueue() ⑤
总体流程分为四步:
- 创建一个接口,内部方法都是接口调用的方法,使用注解的方式添加请求类型、参数和回调数据等;
- 构建一个
Retrofit
对象,并且设置接口的baseUrl
; - 使用
retrofit.create(class)
代理出一个我们第一步创建的接口实例; - 使用接口实例执行具体的接口调用,返回
Call
对象; - 使用
call.enqueu()
方法执行网络请求。
第一步不用具体分析,只需要知道如果使用注解来添加我们请求内容即可,具体如何解析这些注解会在第三步呈现出来,下面直接看第二步Retrofit
的创建过程。
创建Retrofit
Retrofit.Builder().baseUrl(string)
retrofit2.Retrofit.Builder#baseUrl(java.lang.String)
public Builder baseUrl(String baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl)); ①
}
public Builder baseUrl(HttpUrl baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) { ②
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl; ③
return this;
}
Retrofit.Builder().baseUrl(string)
一共做了三个操作:
- 将传入的
url
封装成HttpUrl
对象; - 判断
url
是否是以/
结尾,不是的话直接抛出异常; - 将
HttpUrl
赋值给Builder.baseUrl
。
Builder.build()
retrofit2.Retrofit.Builder#build
public Retrofit build() {
// baseUrl不能为空
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
} ①
// 获取平台,Java/Android
Platform platform = Platform.get(); ②
// 创建OkHttpClient对象
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
} ③
// 创建回调线程池对象
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
} ④
// 创建适配器列表,并且添加默认的适配器
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
List<? extends CallAdapter.Factory> defaultCallAdapterFactories =
platform.createDefaultCallAdapterFactories(callbackExecutor);
callAdapterFactories.addAll(defaultCallAdapterFactories); ⑤
// 创建默认的转换器列表
List<? extends Converter.Factory> defaultConverterFactories =
platform.createDefaultConverterFactories();
int defaultConverterFactoriesSize = defaultConverterFactories.size();
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size() + 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(defaultConverterFactories); ⑥
// 创建Retrofit对象
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
defaultConverterFactoriesSize,
unmodifiableList(callAdapterFactories),
defaultCallAdapterFactories.size(),
callbackExecutor,
validateEagerly); ⑦
}
}
Builder.build()
方法中主要就是创建或者获取一些重要的对象,一共包括6个对象,下面一个个分析下具体作用:
- 第一步判断
baseUrl
是否为空,为空直接抛异常; - 第二步获取
Platform
平台对象,因为我们在Android工程中使用,所以获取的是Android21
或者Android24
其中一个,Platform
定义了回调线程池、调用适配器和转换适配器对象等; - 第三步获取回调线程池对象,会从
Platform
对象中获取默认的线程池; - 第四步获取
CallAdapter.Factory
列表,并且添加从Platform
中获取到的默认CallAdapter.Factory
对象。CallAdapter
的主要作用就是将我们接口返回的对象转换成想要的类型,典型的就是RxJavaCallAdapter
,它就是将默认的Call
转换成Observable
- 第五步获取
Converter.Factory
列表,同时也会从Platform
中获取默认的Converter.Factory
列表。Converter.Factory
的主要作用就是将请求结果通过具体的操作转换成想要的类型,典型的就是GsonConverter
,它就是将String
转换成具体的数据类对象。 - 第六步创建
Retrofit
对象,然后设置上面获取的对象。
Retrofit.cerate()
retrofit2.Retrofit#create
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance( ①
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 判断Service是接口还是类,如果是类直接调用类的方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
Platform platform = Platform.get();
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args); ②
}
});
}
Retrofit.create(class)
方法中可以看出主要的有两步:
- 第一步使用动态代理模式,根据传入的
class
对象代理最终代理出一个实例; - 第二步先判断
platform.isDefaultMethod(method)
,进入Android21
类中此方法默认false
,所以直接看loadServiceMethod(method)
方法即可
-
loadServiceMethod(method)
会创建一个ServiceMethod
对象;- 再调用
ServiceMethod.invoke(args)
方法,这里传入的接口方法的参数
Retrofit.loadServiceMethod()
retrofit2.Retrofit#loadServiceMethod
ServiceMethod<?> loadServiceMethod(Method method) {
// 查看是否命中缓存
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
// 加锁并且双重判断是否命中缓存
result = serviceMethodCache.get(method);
if (result == null) {
// 获取新的ServiceMethod对象,并存入Map中
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
loadServiceMethod()
方法内部逻辑还是比较简单,先是从Map
中获取是否已经存在,不存在再加锁去获取新的ServiceMethod
对象,最后放入缓存Map
中。具体的获取流程还需要进入ServiceMethod.parseAnnotations(retrofit,method)
方法中。
ServiceMethod.parseAnnotations()
retrofit2.ServiceMethod#parseAnnotations
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 创建RequestFactory对象
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);
}
// 返回类型不能为void类型
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
} ②
// 创建HttpServiceMethod对象
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); ③
}
parseAnnotations()
方法中主要做了三件事:
- 第一件就是创建了
RequestFactory
对象,这个接下来分析下这个对象作用是什么; - 第二件通过
Method
获取方法返回值,并判断可用性; - 第三件转到
HttpServiceMethod
中创建HttpServiceMethod
对象,此类是ServiceMethod
的子类。
RequestFactory.parseAnnotations(retrofit, method)
retrofit2.RequestFactory#parseAnnotations
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation); ①
}
// httpMethod不能为空,也就是设置的请求方式GET、POST等
if (httpMethod == null) {
throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
} ②
// 判断请求提是否合规
if (!hasBody) {
if (isMultipart) {
throw methodError(
method,
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError(
method,
"FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
} ③
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
} ④
if (relativeUrl == null && !gotUrl) {
throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError(method, "Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError(method, "Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError(method, "Multipart method must contain at least one @Part.");
}
return new RequestFactory(this); ⑤
}
parseAnnotations()
方法直接调用了内部Builder.build()
方法,build()
方法中,可以细分为五步:
- 第一步通过
parseMethodAnnotation()
解析方法上注解,解析的内容包括:请求方式、请求头、请求地址、是否Multipart
和是否FormUrlEncode
等信息,下面会详细分析; - 第二步判断请求方式,如果为空直接抛异常;
- 第三步判断
Multipart
和FormUrlEncode
注解,如果有请求体的时候,不可以有前面两个注解,否则直接抛异常; - 第四步通过
parseParameter
解析参数上注解,包括Body
、Filed
、Header
和Query
等信息; - 第五步创建
RequestFactory
对象,将Builder
传入进去。
RequestFactory.parseMethodAnnotation()
retrofit2.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;
}
}
parseMethodAnnotation()
主要就是解析出方法上的注解,比如是GET
还是POST
请求,有没有额外添加HEADER
,或者是不是Multipart
、FormUrlEncoded
。
RequestFactory.parseParameter()
retrofit2.RequestFactory.Builder#parseParameter
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(
method, p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
}
.....
return result;
}
parseParameter()
具体的解析流程在parseParameterAnnotation()
方法中,由于此方法源码过于长,此处就不再贴源码了,里面其实就是根据不同的注解类型来解析成对应的ParameterHandler
对象。
具体的类型如下:
@Url
注解,解析出来对应的是ParameterHandler.RelativeUrl()
对象;@Path
注解,解析出来对应的是ParameterHandler.Path()
对象;@Query
注解,解析出来对应的是ParameterHandler.Query()
对象;@QueryName
注解,解析出来对应的是ParameterHandler.QueryName()
对象;@QueryMap
注解,解析出来对应的是ParameterHandler.QueryMap()
对象;@Header
注解,解析出来对应的是ParameterHandler.Header()
对象;@HeaderMap
注解,解析出来对应的是ParameterHandler.HeaderMap()
对象;@Field
注解,解析出来对应的是ParameterHandler.Field()
对象;@FieldMap
注解,解析出来对应的是ParameterHandler.FieldMap()
对象;@Part
注解,解析出来对应的是ParameterHandler.Part()
对象;@PartMap
注解,解析出来对应的是ParameterHandler.PartMap()
对象;@Body
注解,解析出来对应的是ParameterHandler.Body()
对象;@Tag
注解,解析出来对应的是ParameterHandler.Tag()
对象;
这就是所有的方法参数注解类型。
RequestFactory.parseAnnotations()
分析完了之后回到HttpServiceMethod.parseAnnotations()
。
HttpServiceMethod.parseAnnotations()
retrofit2.HttpServiceMethod#parseAnnotations
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
boolean continuationIsUnit = 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 {
continuationIsUnit = Utils.isUnit(responseType);
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType(); ②
}
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations); ③
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(
method,
"'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD")
&& !Void.class.equals(responseType)
&& !Utils.isUnit(responseType)) {
throw methodError(method, "HEAD method must use Void or Unit as response type.");
}
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType); ④
okhttp3.Call.Factory callFactory = retrofit.callFactory; ⑤
if (!isKotlinSuspendFunction) {
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,
continuationIsUnit); ⑦
}
}
这里面的逻辑还是略微比较多的,逐一看下:
- 第一步,判断是否是
Kotlin
的挂起函数,然后通过getGenericParameterTypes
获取方法的返回类型; - 第二步,如果不是
Kotlin
的挂起函数,直接通过getGenericReturnType
获取方法的返回类型,这里的返回类型如果是泛型的话有可能拿不到具体的泛型值; - 第三步创建
CallAdapter
,这里假设我们没有设置任何额外的CallAdapter
,会使用默认的DefaultCallAdapter
对象; - 第四步创建
ConverterAdapter
,这里我们一般使用Gson
来解析响应结果,转换成数据类,这边假设使用的是GsonResponseBodyConverter
对象; - 第五步仅仅是获取
Retrofit
对象中callFactory
; - 第六步和第七步对
Kotlin
的挂起函数做判断,分析过程中默认非挂起函数,直接进入第七步,烦恼会一个CallAdapted
对象。
到这我们发现Retrofit.create()
方法中,动态代理中loadServiceMethod()
方法最终返回的就是CallAdapted
对象,loadServiceMethod()
方法后面直接调用了invoke()
方法,接下来进入CallAdapted.invoke()
方法。
CallAdapter.invoke()
进入CallAdapted
对象中,发现并没有invoke()
方法的实现,只能退而求其次去看它的父类了:
retrofit2.HttpServiceMethod#invoke
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
invoke()
方法中首先创建了一个OkHttpCall
对象,然后调用adapt()
方法。
OkhttpCall
是Retrofit
用来管理发起网络调用和回调的具体类。
CallAdapted.adapt()
retrofit2.HttpServiceMethod.CallAdapted#adapt
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
// 这里的callAdapter为DefaultCallAdapterFactory中CallAdapter
return callAdapter.adapt(call);
}
retrofit2.DefaultCallAdapterFactory#get
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);
}
};
adapt()
方法直接调用callAdapter.adapt()
方法,前面我们说到,默认使用CallAdapter
,它是有DefaultCallAdapterFactory
创建而成,CallAdapter.adapt()
方法中只是创建了一个ExecutorCallbackCall
对象。
到这里我们就清除了,在使用章节第四步生成的Call
其实就是ExecutorCallbackCall
对象,让他调用它的enqueue()
方法就可以发起网络请求。
ExecutorCallbackCall.enqueue()
retrofit2.DefaultCallAdapterFactory.ExecutorCallbackCall#enqueue
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
// 直接使用代理Call的enqueue方法,这里的delegate就是OkHttpCall对象
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
// 主线程中回调结果,Android默认callbackExecutor为MainExecutor
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));
}
});
}
ExecutorCallbackCall.enqueue()
方法很简单,直接调用delegate.enqueue()
,然后将网络请求的结果回调到主线程中去处理。
这里的delegate
从CallAdapted.invoke()
方法可以得知,它就是OkHttpCall
对象,接着我们进入OkhttpCall.enqueue()
方法。
OkHttpCall.enqueue()
retrofit2.OkHttpCall#enqueue
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) { ①
try {
call = rawCall = createRawCall(); ②
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue( ③
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
...
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
...
}
});
}
此方法才是最终调用Okhttp3
发起网络请求最终地点,重要的一共有三步:
- 第一步检查
rawCall
是否为空; - 第二步如果
rawCall
为空,需要通过createRawCall()
来创建OKhttp3.Call
对象; - 使用
Okhttp3.Call.enqueue()
方法来发起异步请求。
到这为止,整个Retrofit
网络请求流程就分析结束了,Retrofit
并没有执行任何网络请求操作,只是将所有方法注解、参数注解解析好之后,交给Okhttp3
来发起具体的网络请求。