前一篇对OkHttp4.2.2源码进行了简单解析,并附上了相应的流程图。直接使用OkHttp还不够方便,所以又诞生了Retrofit。截止本文编写日期,Retrofit最新版为2.6.2,其自身使用OkHttp3.14.4、coroutines1.3.2。虽然Retrofit使用的不是最新版的OkHttp,但也不影响之前分析的流程。
一、流程图
二、简单使用
- 添加依赖
implementation("com.squareup.retrofit2:retrofit:2.6.2")
- 定义请求接口
interface ApiService {
@GET("users/{user}/repos")
suspend fun listRepos( @Path("user") user: String ): FoodResponse<List<Repo>>
}
- 构建Retrofit生成Api实例
val baseUrl = "https://api.github.com/"
val okClient = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
......
.build()
Retrofit.Builder()
.baseUrl(baseUrl)
.client(okClient) //有默认,非必须
.addConverterFactory(GsonConverterFactory.create())
.build()
val service = retrofit.create(ApiService::class.java)
- 发起请求
//1. 回调方式
service.listRepos1("zx").enqueue(object : Callback<List<Repo>> {
override fun onFailure(call: Call<List<Repo>>, t: Throwable) {
}
override fun onResponse(call: Call<List<Repo>>, response: Response<List<Repo>>) {
}
})
//2. 协程方式
val repos = service.listRepos("zx")
//3. RxJava等
})
三、源码解析
通过上面4步,演示了如何通过Retrofit发起一次网络请求,接下来就根据上面的流程看看源码,点到即止。
构建Retrofit
在构建Retrofit这步我们主要关注3个,分别是 Builder方法、 baseUrl()方法和 build()方法
- Builder
public Builder() {
// 平台获取,Platform我们在OkHttp分析中也见到过
this(Platform.get());
}
- baseUrl
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();
// 检查baseUrl是否以/结尾,不是就抛出异常
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
baseUrl的作用就不说了,这里我们看下注释那行,baseUrl不以 / 结尾,就会抛出异常。
需要注意的是这里的baseUrl类型是HttpUrl类型,所以跟我们使用设置的String是不一样的。HttpUrl.get对我们设置进行了处理,所以我们的String类型baseUrl不以 / 结尾不一定会得到异常。
- build
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
//如果没有设置callFactory,则默认使用OkHttpClient,也就是我们常说得Retrofit默认使用OkHttp
//OkHttpClient实现了okhttp3.Call.Factory接口
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//callbackExecutor
//如果没有设置回调执行者,则使用平台默认回调执行者
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());
// 构建 Retrofit
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
build方法主要是参数的处理(对null值和平台默认值的处理)并构建出Retrofit实例。
上面多次出现Platform字眼,接下来看看这个类里做了什么?
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();
}
......
@IgnoreJRERequirement // Only classloaded and used on Java 8.
static class Java8 extends Platform {
......
}
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.<Converter.Factory>emptyList();
}
@Override
int defaultConverterFactoriesSize() {
return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
}
// Android 主线程执行者
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
}
总结3点:
- 通过findPlatform方法可以看出2.6.2支持Android和Java。(记得2.0.1的时候还有iOS字样,另外GitHub最新代码把Java8也移除了。)
- 设置了平台默认回调执行者(Handler 主线程)、默认适配工厂和默认转换工厂
- Java8 和 Android 24是一个分界点(具体可以看CompletableFutureCallAdapterFactory和OptionalConverterFactory)
创建Api实例
上面分析了Retrofit的构建过程,紧接着看看创建Api实例部分。实际创建Api实例似乎很简单,只需要如下一行代码:
val service = retrofit.create(ApiService::class.java)
难道真这么简单么?接着往下看:
public <T> T create(final Class<T> service) {
// 校验 Service Interface 是否满足要求
Utils.validateServiceInterface(service);
if (validateEagerly) {
// 是否需要提前验证Service Interface方法,
// true:在调用create时就把相应方法进行处理加入到serviceMethodCache缓存起来
// false:在调用执行InvocationHandler.invoke时再做处理和缓存
// true 和 false最终都是调用loadServiceMethod
eagerlyValidateMethods(service);
}
// 使用动态代理拿到请求接口所有注解配置,创建网络请求接口实例
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},
new InvocationHandler() {
......
});
}
// 提前验证Service Interface方法
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method) && !Modifier.isStatic (method.getModifiers())) {
// isDefaultMethod 是否平台默认方法,2.6.2返回的fasle
// isStatic 是否被static修饰
loadServiceMethod(method);
}
}
}
果然,这样看很简单呐。这一步先不针对loadServiceMethod及其后续操作进一步分析,放在发起请求invoke执行时再看,因为平时我也没有设置过validateEagerly。
发起网络请求
public <T> T create(final Class<T> 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];
// 执行newProxyInstance出来实例中的方法
@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默认方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 平台默认方法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 加载Service Interface方法,调用invoke创建OkHttpCall发起请求
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
// ConcurrentHashMap支持多线程访问并且线程安全
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?> loadServiceMethod(Method method) {
// 获取缓存
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// 解析注解,生成ServiceMethod
result = ServiceMethod.parseAnnotations(this, method);
// serviceMethodCache 加入缓存
serviceMethodCache.put(method, result);
}
}
return result;
}
跟进ServiceMethod.parseAnnotations
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 解析注解参数
// 主要解析请求类型 baseUrl relativeUrl 以及方法注解 参数类型 参数注解等等
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
......
// HttpServiceMethod是跟进ServiceMethod子类
// 在parseAnnotations中创建了callAdapter和responseConverter
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
// 创建OkHttpCall,通过adapt发起请求
abstract @Nullable
T invoke(Object[] args);
}
再跟进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;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
// 是 Kotlin Suspend 方法
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);
// 返回结果被Response包含 如:Response<T>
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();
}
// 根据retrofit, method, adapterType, annotations 创建CallAdapter
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)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
// 根据retrofit, method, adapterType 创建Converter
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
// 非Kotlin Suspend方法
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//Kotlin Suspend方法且被Response包含
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//Kotlin Suspend方法且未被Response包含
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
HttpServiceMethod.parseAnnotations最后返回了HttpServiceMethod,回到Retrofit.create方法执行invokede 调用。HttpServiceMethod中具体实现了invoke如下:
@Override final @Nullable ReturnT invoke(Object[] args) {
//创建Call对象
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
// adapt 也是个抽象方法,具体实现在CallAdapted,SuspendForResponse,SuspendForBody
return adapt(call, args);
}
上面还有比较重要的2点 createCallAdapter、createResponseConverter 方法,这里看看CallAdapter的创建。通过createCallAdapter -> retrofit.callAdapter -> nextCallAdapter:
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
......
int start = callAdapterFactories.indexOf(skipPast) + 1;
// 遍历 Retrofit.build 构建的 callAdapterFactories 集合,寻找合适的适配工厂
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
......
throw new IllegalArgumentException(builder.toString());
}
怎么来找对应的callAdapter,其实很简单,根据特定类型就可以了(比如如果返回Call 就是默认的,被suspend修饰就是协程,可以看看CallAdapterFactory的get方法)。
接下来看看实现了HttpServiceMethod的SuspendForBody是怎么实现的:
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
private final boolean isNullable;
......
@Override protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
//noinspection unchecked Checked by reflection inside RequestFactory.
Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
/** 像在await和awaitNullable内部一样, 对OkHttp Call.enqueue()的调用有时可以在异常返回之前调用提供的回调, 而调用栈帧可以返回。 协程将拦截Continuation的后续调用,并同步引发异常。 如果未在接口方法中声明检查的异常,则Java代理无法引发检查的异常。 为了避免将同步检查的异常包装在UndeclaredThrowableException中, 将其拦截并提供给帮助程序,该帮助程序将强制执行挂起操作, 以便可以将其传递给继续操作以绕过此限制。 **/
try {
// 调用具体的扩赞方法
return isNullable
? KotlinExtensions.awaitNullable(call, continuation)
: KotlinExtensions.await(call, continuation);
} catch (Exception e) {
return KotlinExtensions.yieldAndThrow(e, continuation);
}
}
}
接下来是扩展方法await实现如下:
suspend fun <T : Any> Call<T>.await(): T {
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel()
}
// 实际就是调用call.enqueue
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
val body = response.body()
if (body == null) {
val invocation = call.request().tag(Invocation::class.java)!!
val method = invocation.method()
val e = KotlinNullPointerException("Response from " +
method.declaringClass.name +
'.' +
method.name +
" was null but response body type was declared as non-null")
continuation.resumeWithException(e)
} else {
//携带数据切回挂起处,等同于callback
continuation.resume(body)
}
} else {
continuation.resumeWithException(HttpException(response))
}
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
当执行到KotlinExtensions.await/awaitNullable时,就会执行相应扩展函数挂起。不难发现最终还是通过Call.enqueue发起请求,得到相应结果则通过相应的resume函数恢复挂起。这个Call对象即是上面invoke中的OkHttpCall,而它的创建方式如下。不难猜测最终发起请求和数据转换都在它里面,所以上面的await扩展中调用的enqueue方法也在其中实现。
//避免回滚上去看OkHttpCall,所以在这儿由cv了一次
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
看看OkHttpCall的enqueue方法
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
......
//经过一些列判断操作 最终发起请求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
// 解析Response
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
......
});
}
// 解析响应数据
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
......
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//responseConverter 最终通过Converter解析完毕数据
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
......
}
四、总结
Retrofit通过接口注解简化网络请求配置,采用动态代理加载解析注解执行方法。然后通过OkHttpCall发起请求,获得响应后通过Converter进行数据转换后交给CallAdapter把最终数据交给开发者。
通过对Retrofit的使用和源码了解,Retrofit确实是封装了OkHttp,并且大量使用注解和设计模式,比如建造者模式、动态代理模式、工厂模式、适配器模式等等。
虽然这是基于2.6.2解析,但是看最新提交已有些许改版,前面也提到一点儿。
五、补充
线程切换
因为上面是用的协程,所以没有看到是如何进行线程切换的,现在我们来see 1 see,注释都加了。如下:
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
private final @Nullable Executor callbackExecutor;
// 传入参数为回调执行者,还记得在哪儿传入的么?
// Retrofit的build方法,根据相关平台里面来的
DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
// 此方法用于createCallAdapter
@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);
//获取执行者(协程不需要)
final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
// 返回call,非协程方式用ExecutorCallbackCall包一层
return executor == null
? call
: new ExecutorCallbackCall<>(executor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
// 此处的delegate就是OkHttpCall
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
//回调执行者完成线程切换
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
// 通过callback回调了结果
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> execute() throws IOException {
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
}
今天的文章Retrofit2.6.2源码解析分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/22941.html