前言
如果还不了解Retrofit的,建议先看看我之前文章,起码对Retrofit的使用有一个大概的了解。
传送门:
- Retrofit教程之【新手入门】篇
- Retrofit教程之【深入源码】篇 ⬅️当前位置
- Retrofit教程之【设计模式】篇
这里会围绕Retrofit的请求过程来分析源码,涉及的代码以及文字可能会比较长,建议先阅读Retrofit教程之【新手入门】篇 再来阅读这篇文章会更加容易。
另外完整的代码我已经上传到了github,有需要可以去下载。
网络请求过程
使用Retrofit完成一次网络请求过程,大概分为几个步骤:
首先看创建Retrofit的代码
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
这里是采用了一个经典的Facade(门面模式)+Builder(创建者模式)来设计Retrofit,目的就是将Retrofit内部复杂的创建过程给屏蔽,并且能够简单的构建。
然后调用Retrofit.create方法来创建具体的接口
ApiService service = retrofit.create(service);
我们定位到Retrofit.create代码里看一下:
public final class Retrofit {
public <T> T create(final Class<T> service) {
// 校验声明的接口及参数是否合法
// 这里需要注意的是,你的接口不能是Void的或者其他类型,否则会报错
validateServiceInterface(service);
// 动态代理创建出具体的Service
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
// 获取当前系统平台信息,具体区别是有无java8
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 (method.getDeclaringClass() == Object.class) {
//这里回调的就是在接口中声明的具体的参数
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
// 如果是默认的,则调用默认的方式只在API26+有效
// 否则 调用loadServiceMethod
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
...省略代码...
}
这里面需要注意的是validateServiceInterface方法,这里面会根据validateEagerlyboolean变量对接口进行提前校验,代码如下:
if (validateEagerly) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
}
然后再回到loadServiceMethod()方法:
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;
}
这里我们注意到,serviceMethodCache这个Map会缓存住已经解析过注解的ServiceMethod对象。这里其实是用了一个非常经典的享元模式来处理这种有很多对象创建的场景,好处就是大大减少对象的创建,降低系统的内存,使效率提高。
如果从serviceMethodCache获取不到对应的value,则使用ServiceMethod进行注解的解析。注解的解析最后是交给了RequestFactory来处理
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
解析注解
然后点开RequestFactory源码,可以发现,所有你在接口中加上的注解,都会在这里被解析成对应的网络请求的参数,这里就不放所有代码了。
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
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);
}
}
完成上面的解析,才会返回一个完整的我们声明的API接口实现类的实例,最后返回Call对象,发起真正的网络请求。
好,我们回过头来看一下,整个的流程:
找到“真凶”
接下来就是真正的网络请求了
Call<Result<NewsResult>> call = service.getNewsByPost(map);
call.enqueue(new Callback<Result<NewsResult>>() {
@Override
public void onResponse(Call<Result<NewsResult>> call, Response<Result<NewsResult>> response) {
updateResult(response);
}
@Override
public void onFailure(Call<Result<NewsResult>> call, Throwable t) {
}
});
我们看下Call对象的源码,可以得出Call对象是负责发起请求,取消请求的接口协议,那么具体的调用,肯定是在具体的实现类里。
public interface Call<T> extends Cloneable {
/**
* Asynchronously send the request and notify {@code callback} of its response or if an error
* occurred talking to the server, creating the request, or processing the response.
*
* 异步发送请求,如果和服务器发起会话,创建请求,或者处理Response都会通知到callback
*/
void enqueue(Callback<T> callback);
void cancel();
Response<T> execute() throws IOException;
}
点击Call接口,发现有2个类实现了它
- ExecutorCallbackCall
- OkHttpCall
然后通过debug发现最终是走向了ExecutorCallbackCall中的实现,看代码:
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
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(DefaultCallAdapterFactory.ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(DefaultCallAdapterFactory.ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(DefaultCallAdapterFactory.ExecutorCallbackCall.this, t));
}
});
}
我们注意到equeue()方法里的实现,又交给了一个Call类型的delegate对象,
那么你会好奇,明明已经实现了,为什么又委托给另一个实现类?
而且已知的实现类就2个,难道另一个是OkHttpCall?
没错,这个Call的实现类就是OkHttpCall,这其实是因为在一开始创建Retrofit对象的时候,也就是在build的时候就已经初始化了一个默认的CallAdapterFactory,代码如下:
// 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));
那它又是在什么时候初始化的呢?
这里调用的路径比较长,我们只要知道最终是在HttpServiceMethod的parseAnnotations()方法里。
知道这个delegate对象是由OkHttpCall,接下来我们转到equeue方法这里:
public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
// 此处代码略
synchronized (this) {
if (call == null && failure == null) {
try {
// 创建原始的Call对象
call = rawCall = createRawCall();
} catch (Throwable t) {
}
}
}
// 此处代码略
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) {
return;
}
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
});
}
通过代码可以发现,这里又创建了一个Call对象,当然不是上文的Call,而是okhttp3.Call对象,这里通过创建指向了RealCall对象,也就是交给它来处理加入的请求。
Dispatcher分发
接下来就是重头戏了,
final class RealCall implements Call {
final OkHttpClient client;
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
// 划重点!!!!
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
}
一下子出来了3个新鲜玩意:
- OkHttpClient(这个应该不陌生)
- dispatcher。
- AsyncCall。
咱们一一来看,第一个不说了,大家都应该知道。
第二个,点开Dispatcher源码,看注释,
Policy on when async requests are executed.Each dispatcher uses an ExecutorService to run calls internally. If you supply your own executor, it should be able to run the configured maximum number of calls concurrently.
翻译过来就是个自定义线程池,如果你想玩,你也可以自己搞一个。
再看源码:
public final class Dispatcher {
private int maxRequests = 64;// 最大请求数64
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
/** Executes calls. Created lazily. */
private @Nullable
ExecutorService executorService;
/** Ready async calls in the order they'll be run. */
private final Deque<RealCall.AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall.AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
我们可以总结出,这个线程池有几个特点:
- 最多能处理64个请求;
- 每个主机最多能处理5个请求;
- 可以自定义线程池,但是必须能够定义的最大请求数maxRequests;
- 维持着3种队列,来处理不同状态的任务;
然后是AsyncCall,这其实是RealCall的一个内部类,等会再说。
再回到一开始加入AsynCall的代码:
client.dispatcher().enqueue(new AsyncCall(responseCallback));
也就是new了一个AsyncCall对象交给Dispatcher线程池类进行分发执行了。那么在执行的时候,通过代码可以发现:
void enqueue(RealCall.AsyncCall call) {
synchronized (this) {
// 添加到待执行的队列中
readyAsyncCalls.add(call);
// 。。。此处代码略。。。
// 执行
promoteAndExecute();
}
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<RealCall.AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
// 1. 遍历readyAsyncCalls
for (Iterator<RealCall.AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
RealCall.AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
asyncCall.callsPerHost().incrementAndGet();
// 2. 过滤出可用的添加到executableCalls队列中
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
// 3. 遍历executableCalls,并执行
for (int i = 0, size = executableCalls.size(); i < size; i++) {
RealCall.AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
最后是调用到了AsyncCall里的execute()方法,查看源码
@Override protected void execute() {
// 此处代码略
try {
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
}
// 此处代码略
}
终于看到和返回结果相关的Response对象了,这一路走来我容易吗我5555!!
但是接下来我发现,离终点还远着呢。
击鼓传花之Interceptor
接下来也是Retrofit比较重要的部分,那就是:Interceptor。
下面我们把重点放到getResponseWithInterceptorChain方法上。
往往一个方法名起的够长,我就知道事情没那么简单!
ok,看源码!
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
// 1. 添加Interceptor
interceptors.add(new RetryAndFollowUpInterceptor(client));
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
interceptors.add(new CallServerInterceptor(forWebSocket));
// 2. 交给Interceptor.Chain,
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//3. 递归调用
Response response = chain.proceed(originalRequest);
}
由于代码过长,省略了部分代码。
一下子,又多了这么多类,这都是干嘛的?
这个方法又是什么意思?
首先,看我在代码里的注释,1.2.3明白了吗,不明白再看一遍!
这里的Interceptor采用了JAVA设计模式中又很经典的一个责任链模式(Chain of Responsibility),如果不理解这个设计模式的话,那这段代码理解起来会有些难度,不过你可以通俗的理解为“击鼓传花”,大概也就明白了。
不过这里可以理解为 “拦截链”,只是个名字,千万不要把他认为是责任链模式的名字。按照代码中所添加的拦截器,总结如下:
不过需要注意的是,最后的网络真正的请求是在最后一个CallServerInterceptor中完成返回Response对象的。
完美转换Converter
拿到Response对象还没完,因为返回的数据都是原始数据,没有经过处理。由于我们之前添加了GsonConverterFactory,所以我们的数据还要经过Gson转换器来进行数据转换。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
转换实在OkHttpCall中的parseResponse方法中实现的,看源码:
retrofit2.Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
OkHttpCall.ExceptionCatchingResponseBody catchingBody = new OkHttpCall.ExceptionCatchingResponseBody(rawBody);
try {
// 数据转换
T body = responseConverter.convert(catchingBody);
return retrofit2.Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
那么这个responseConverter对象又是在什么时候初始化的呢?
通过源码可以定位实在Retrofit通过动态代理反射创建接口时的InvocationHandler的invoke()方法里。
最后,在通过在回调处理我们的数据。
整体的流程,我用processOn工具整理出来个流程图:
总结
- 实际网络请求过程并没有没有深入分析,因为实际的网络请求更复杂,这里只是结合着Retrofit的源码来进行分析。
- 看源码的过程,不仅是一个学习的过程,更要思考作者是如何设计的。
- 设计模式在这里运用的只能说是一个字:秒!其实,仔细想想,责任链模式不是早应该运用在这里了么?!!
- 注解式的框架有很多种,Retrofit的注解算是运用的恰到好处!
- 当然最牛逼的还是他的解耦方式,把请求过程每一个步骤所涉及的类都充分解耦,这种设计思想没有多年的架构实战经验是设计不出来的。