Get into the habit of writing together! This is the second day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .
Introduction
Retrofit turns your HTTP API into a Java interface.
Retrofit converts HTTP API to Java interface
This article is based on the Retrofit
source code analysis of version 2.9.0!
Dependency added:
com.squareup.retrofit2:retrofit:2.9.0
use
Let's take the Demo of the official website as an example to see the simplest use:
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() ⑤
复制代码
The overall process is divided into four steps:
- Create an interface, the internal methods are all methods called by the interface, and use annotations to add request types, parameters, and callback data;
- Build an
Retrofit
object and set the interfacebaseUrl
; - Use
retrofit.create(class)
the proxy to create an instance of the interface we created in the first step; - Use the interface instance to perform specific interface calls and return
Call
objects; - Use
call.enqueu()
methods to perform network requests.
The first step does not need specific analysis, just need to know that if we use annotations to add the content of our request, how to parse these annotations will be presented in the third step, let’s look directly at Retrofit
the creation process of the second step.
Create 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)
A total of three operations were done:
url
Encapsulate the incoming object into anHttpUrl
object;- Determine
url
whether it is the/
end, if not, throw an exception directly; - will be
HttpUrl
assigned toBuilder.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()
The main method is to create or obtain some important objects, including a total of 6 objects, the following analysis of the specific functions:
- 第一步判断
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
是否为空; - In the second step, if it
rawCall
is empty, you needcreateRawCall()
to create anOKhttp3.Call
object through it; - Use
Okhttp3.Call.enqueue()
methods to initiate asynchronous requests.
So far, the Retrofit
analysis of the entire network request process is over, Retrofit
and no network request operation is performed, but after all method annotations and parameter annotations are parsed, they are handed over Okhttp3
to initiate specific network requests.