OKHttp3--调用对象RealCall源码解析【四】_没有鱼了的博客-CSDN博客
一:概述,当我们封装好 Request后需要执行这个请求,但是 OkHttp并不是直接执行 Request ,而是将 Request又封装了一层 Call对象,一个Call对象代表一个已经准备好的请求(Request), Call可以取消,同时一个 Call对象代表了一个 请求/响应 (request/response)流 。
二:Call只是一个请求接口,具体的实现是 RealCall ,不管是同步请求还是异步请求,请求的对象均是RealCall . 当我们执行同步请求时会调用它的execute方法,执行异步请求会调用enqueue方法
三:RealCall源码
RealCall的代码并不复杂,也没有做过多的操作,而且同步异步的请求在RealCall中的操作基本差不多,只不过同步请求是在当前线程执行,而异步请求是封装了一个子线程AsyncCall去执行请求;而关于具体的网络请求过程都在拦截器里进行
/**
* 一个Call封装一对Request和Response,能且仅能被执行一次。并且Call可以被取消。
*/
final class RealCall implements Call {
//OKHttp客户端
final OkHttpClient client;
//重试和重定向拦截器
final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
//RealCall状态监听器
final EventListener eventListener;
//请求对象
final Request originalRequest;
final boolean forWebSocket;
// RealCall是否执行过
private boolean executed;
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
this.eventListener = eventListenerFactory.create(this);
}
/** 返回初始化此Call的原始请求 */
@Override
public Request request() {
return originalRequest;
}
/** 进行同步请求
* 立即发出请求,一直阻塞当前线程,直到返回结果或者报错
* 可以使用Response.body获取结果
* 为了复用连接,需要调用Response.close关闭响应体
*/
@Override
public Response execute() throws IOException {
synchronized (this) {
//同一个RealCall,只能执行一次
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//打印堆栈信息
captureCallStackTrace();
try {
//加入分发器中的正在执行的同步请求队列
client.dispatcher().executed(this);
//获取请求结果
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
//通知分发器请求完成,从队列移除
client.dispatcher().finished(this);
}
}
private void captureCallStackTrace() {
Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
}
/**
* 进行异步请求
* 至于何时执行这个请求由分发器决定
* 通常是立即执行,除非当前有任务在执行或不符合限制条件
* 如果不能立即执行,会被保存到等待执行的异步请求队列
* 请求结束后,会通过回调接口将结果返回
*/
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
//实例化一个线程AsyncCall交给分发器,由分发器中的线程池执行这个线程
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
//取消这个RealCall 如果请求已经有返回了,那么就不能被取消了
@Override
public void cancel() {
retryAndFollowUpInterceptor.cancel();
}
//判断是否执行过
@Override
public synchronized boolean isExecuted() {
return executed;
}
//判断是否取消了
@Override
public boolean isCanceled() {
return retryAndFollowUpInterceptor.isCanceled();
}
//复制一个相同的RealCall
@SuppressWarnings("CloneDoesntCallSuperClone")
@Override public RealCall clone() {
return new RealCall(client, originalRequest, forWebSocket);
}
//StreamAllocation协调Connections,Streams,Calls三者之间的关系
StreamAllocation streamAllocation() {
return retryAndFollowUpInterceptor.streamAllocation();
}
//异步请求线程
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
//主机名
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
//当分发器的线程池执行该对象时,该方法被调用
@Override
protected void execute() {
//保证onFailure只被回调一次
boolean signalledCallback = false;
try {
//通过拦截器获取返回结果
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
//如果请求被取消,回调onFailure
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
// 正常情况,调用onResponse
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
// 如果上面回调过,这里就不再进行回调,保证onFailure只会被调用一次
if (signalledCallback) {
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
//通知分发器请求结束,从队列中移除该请求
client.dispatcher().finished(this);
}
}
}
/**
* Returns a string that describes this call. Doesn't include a full URL as that might contain
* sensitive information.
*/
String toLoggableString() {
return (isCanceled() ? "canceled " : "")
+ (forWebSocket ? "web socket" : "call")
+ " to " + redactedUrl();
}
//返回包含此URL的字符串,无用户名,密码,查询信息
String redactedUrl() {
return originalRequest.url().redact();
}
//依次执行拦截器链中的拦截器获取结果
Response getResponseWithInterceptorChain() throws IOException {
List<Interceptor> interceptors = new ArrayList<>();
//添加自定义拦截器
interceptors.addAll(client.interceptors());
//添加重试和重定向拦截器
interceptors.add(retryAndFollowUpInterceptor);
//添加桥接拦截器
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//添加缓存拦截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//添加链接拦截器
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//添加网络拦截器
interceptors.addAll(client.networkInterceptors());
}
//添加连接服务器拦截器,主要负责将我们的Http请求写进网络的IO流中
interceptors.add(new CallServerInterceptor(forWebSocket));
//构建拦截器链依次执行每一个拦截器
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
}
五:异步请求
异步请求会走到内部的enqueue方法
@Override
public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
// 实例化 AsyncCall对象
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
首先它是RealCall的内部类,我们都知道异步请求是在子线程执行的,但是到这里我们还没有看出来子线程的影子,那我们就需要看下RealCall的父类了
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@Override
protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
NamedRunnable实现了Runnable接口,从这里可以看出AsyncCall确实是在子线程执行网络请求
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
六:同步请求
同步请求会走到内部的execute方法
第一步:首先出现一个同步代码块,对当前对象加锁,通过一个标志位executed判断该对象的execute方法是否已经执行过,如果执行过就抛出异常;这也就是同一个Call只能执行一次的原因
第二步:这个是用来捕获okhttp的请求堆栈信息,不是重点
第三步:调用Dispatcher的executed方法,将请求放入分发器,这是非常重要的一步
第四步:通过拦截器连获取返回结果Response
第五步:调用dispatcher的finished方法,回收同步请求
@Override
public Response execute() throws IOException {
//第一步
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//第二步
captureCallStackTrace();
try {
//第三步
client.dispatcher().executed(this);
//第四步
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
//第五步
client.dispatcher().finished(this);
}
}
第三步和第五步都在分发器内部处理,我们重点看下 第四步
这里实例化一个List,用来存放Interceptor对象,主要是OKHttp提供的5种拦截器
接下来实例化了一个拦截器链对象,在这个拦截器链里依次执行每个拦截器
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}