0.前言
终于到了源码分析系列的Retrofit篇了。有关retrofit源码分析的文章网上有很多,但是都是属于旧版本的,本文基于retrofit2的2.6.0版本给大伙简单介绍一下。
retrofit2严格上讲不算一个独立的框架,而是一个网络请求框架的封装框架——对OkHttp的封装,其内部使用了大量的设计模式,具有很强的可拓展性以及可以与其他框架实现无缝对接,也因此其源码阅读起来比较难,虽然代码不多。其内部使用了注解和动态代理,还不了解动态代理的建议先去了解一下,这对阅读retrofit源码很有帮助。
1.使用
首先是导入包:
//retrofit2
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
这里使用的转换器和适配器为gson和rxjava。接下来看看它的简单使用:
首先是OkHttpClient
private val okHttpClient = OkHttpClient()
.newBuilder()
.addInterceptor { chain ->
val request = chain.request()
.newBuilder()
.addHeader("Content-Type", "application/json;charset=UTF-8")
.addHeader("Grpc-Metadata-sessionkey", if (App.getInstance().session_key == null) "" else App.getInstance().session_key)
.build()
chain.proceed(request)
}
.build()
这里将retrofit与OkHttp结合使用。关于OkHttp的源码解析,笔者这篇文章中已有解析,此处不再解析。接着往下看:
创建Retrofit
private val retrofit = Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(HttpAddress.BASE)
.client(okHttpClient)
.build()
与OkHttp类似,接下来创建request:
val netRequest = retrofit.create(NetRequest::class.java)
NetRequest接口:
interface NetRequest {
@POST("task/task_detail")
fun createTaskDetail(@Body `object`: Any): Observable
@GET("task/task_detail")
fun getCall():Call
}
bean类:
package beans.response;
import java.util.List;
public class TaskDetailBean {
private int code;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
然后就可以请求了:
val create=netRequest.create(`object`)
请求结果使用Call处理
create.enqueue(object : Callback{
override fun onFailure(call: Call?, t: Throwable?) {
}
override fun onResponse(call: Call?, response: retrofit2.Response?) {
}
})
总结起来就是四个步骤:创建retrofit、创建request、发起请求、处理结果
接下来就从这四个步骤逐步深入解析它的源码。
2.源码解析
- Retrofit.Builder()
先来看看Builder:
public Builder() {
this(Platform.get());
}
Builder(Platform platform) {
this.platform = platform;
}
Builder很简单,就是获取到Platform后赋值,Platform即获取到平台,入Android和java8,代码如下:
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();//重点
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
}
这里重点看一下Android怎么处理:
static class Android extends Platform {
@IgnoreJRERequirement // Guarded by API check.
@Override boolean isDefaultMethod(Method method) {
if (Build.VERSION.SDK_INT < 24) {
return false;
}
return method.isDefault();
}
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override List extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return Build.VERSION.SDK_INT >= 24
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
@Override int defaultCallAdapterFactoriesSize() {
return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
}
@Override List extends Converter.Factory> defaultConverterFactories() {
return Build.VERSION.SDK_INT >= 24
? singletonList(OptionalConverterFactory.INSTANCE)
: Collections.emptyList();
}
@Override int defaultConverterFactoriesSize() {
return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());//重点
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
可以看到Android是Platform的内部类,内部维护了一个handler 用于线程的切换。
- addCallAdapterFactory与addConverterFactory
获取到Builder之后,根据建造者模式可知,接下来就可以逐步往里面添加”材料“来配置Retrofit了:
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
callAdapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
这里主要就是将其转换的方法和适配方法加入到列表中,以备后续调用。
- build
熟悉建造者模式的可以猜到,这一步就是创建retrofit对象了(OkHttp,Glide这些比较大的框架都采用了建造者模式,所以说框架其实都差不多)
public Retrofit build() {
//baseUrl 不能为空
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//客户端Client
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 callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
List 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());
//创建Retrofit对象
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
}
果不其然,获取到了Retrofit对象了,复杂的对象就该用建造者模式创建。
- create
获取到retrofit对象之后,接下来调用其create方法通过动态代理获取到接口代理:
public T create(final Class service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(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.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
//获取ServiceMethod
ServiceMethod> loadServiceMethod(Method method) {
//从缓存中获取
ServiceMethod> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);//重点
serviceMethodCache.put(method, result);//存进去
}
}
return result;
}
使用动态代理,如此一来一旦调用此方法将需要代理的接口传递过来之后就会自动执行InvocationHandler的invoke方法。
ServiceMethod对请求方法和参数等信息进行封装:
abstract class ServiceMethod {
static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);//代码1
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);//代码2
}
abstract @Nullable T invoke(Object[] args);
里面只有parseAnnotations方法和invoke方法(由子类HttpServiceMethod实现)。
先来看看 RequestFactory.parseAnnotations方法做了什么:
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
等等,Builder和build?对,没错,建造者模式,这厮要搞事了!
按照惯例,先来看看Builder,不用说,肯定是内部类啦:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
其构造方法很简单,果不其然的对一些参数进行了初始化,然后就是build老弟了:
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
/代码1,/解析注解
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(method,
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError(method, "FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler>[parameterCount];
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);//返回RequestFactory对象了!
}
前面是一些条件判断,判断方法和方法体是否为空或有误等。重点看
parseMethodAnnotation(annotation);
方法:
//对注解的解析
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;
}
}
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {
throw methodError(method, "Only one HTTP method is allowed. Found: %s and %s.",
this.httpMethod, httpMethod);
}
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
return;
}
// Get the relative URL path and existing query string, if present.
int question = value.indexOf('?');
if (question != -1 && question < value.length() - 1) {
// Ensure the query string does not have any named parameters.
String queryParams = value.substring(question + 1);
Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
if (queryParamMatcher.find()) {
throw methodError(method, "URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
通过注解的解析,获取到对应的请求类型和实际的请求Url。
最后返回到ServiceMethod中,继续往下看
HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)
static HttpServiceMethod parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
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.
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 {
adapterType = method.getGenericReturnType();
}
CallAdapter 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)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
Converter 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) new SuspendForResponse<>(requestFactory,
callFactory, responseConverter, (CallAdapter>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod) new SuspendForBody<>(requestFactory,
callFactory, responseConverter, (CallAdapter>) callAdapter,
continuationBodyNullable);
}
}
//返回CallAdapter
private static CallAdapter createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
try {
//noinspection unchecked
return (CallAdapter) 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);
}
}
SuspendForBody(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
Converter responseConverter,
CallAdapter> callAdapter, boolean isNullable) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
this.isNullable = isNullable;
}
SuspendForResponse(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
Converter responseConverter,
CallAdapter> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
代码比较多,挑重点来看。重点是创建了callAdapter和responseConverter,这两个东西的用处前面已经说过了。
之后就是调用HttpServiceMethod的adapt方法
@Override final @Nullable ReturnT invoke(Object[] args) {
Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
@Override protected ReturnT adapt(Call call, Object[] args) {
return callAdapter.adapt(call);
}
这里调用callAdapter.adapt(call);,具体的由于这里使用的是rxjava2的adapter,使用跑到RxJava2CallAdapter里面去看:
@Override public Object adapt(Call call) {
Observable> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return observable;
}
可以看到最后是将结果以observable的方式返回了。