从实际使用开始
OKHttp请求分为同步和异步,同步写法和异步写法分别如下:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://www.baidu.com").build();
Call call =client.newCall(request);
//同步写法,直接拿到结果,需要注意try/catch
Response response = call.execute() ;
//异步写法,通过Callback回调拿到结果
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
newCall会返回一个RealCall对象,所以实际上同步时,执行的是RealCall里的execute,异步则是RealCall的enqueue方法。
同步异步的区别
同步
同步时,通过下面代码可以知道,RealCall的execute,调用的是Dispatcher的executed方法,将call加入runningSyncCalls队列,然后从getResponseWithInterceptorChain拿到result。这个getResponseWithInterceptorChain方法异步也会调用,后面会说。
同步时,RealCall的execute方法:
//RealCall.java
@Override public Response execute() throws IOException {
synchronized (this) {
//是否已经执行过,是则抛出异常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
Dispatcher的executed方法:
//Dispatcher.java
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
异步
而异步时,RealCall的enqueue调用的是Dispatcher的enqueue,传入AsyncCall实例,AsyncCall负责新建一个任务去执行具体请求。
//RealCall.java
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
//是否已经执行过,是则抛出异常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
无论同步异步,最开始都会判断当前call是否已经执行过,如果执行过则不再重复执行而是抛出异常。
再看Dispatcher里的enqueue方法,通过线程池excutorService来实现并发。如果存储正在执行的Call的runningAsyncCalls队列没满,则把新的Call加入其中(这点跟同步是一样的),并立即在线程池executorService中执行,如果满了,就会放到readyAsyncCalls队列中等待runningAsyncCalls空出位置来。
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//加到执行队列
runningAsyncCalls.add(call);
//执行Call
executorService().execute(call);
} else {
//加入准备队列,等执行队列有空则加入
readyAsyncCalls.add(call);
}
}
顺便说下,这个executorService线程池是一个高并发低阻塞的线程池,最大可以同时建Integer.MAX_VALUE个线程来执行请求任务,而执行完的空余任务只能存活60秒就会被清理掉:
//Dispatcher.java
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
ThreadPoolExecutor的构造方法:
/**
* @param corePoolSize 最小并发线程数,如果是0的话,空闲一段时间后所有线程将全部被销毁
* @param maximumPoolSize 最大线程数,当任务进来时可以扩充的线程最大值,当大于了这个值就会根据丢弃处理机制来处理
* @param keepAliveTime 当线程数大于corePoolSize时,多余的空闲线程的最大存活时间
* @param unit 时间单位
* @param workQueue 工作队列,先进先出
* @param threadFactory 单个线程的工厂
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
上面说到,AsyncCall会负责新建一个线程去执行具体请求,实际方法为AsyncCall的execute。AsyncCall继承自NamedRunnable,在这个任务会在新线程中去请求并拿到response:
//RealCall的内部类AsyncCall的execute方法
@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) {
//省略异常。。。
} finally {
client.dispatcher().finished(this);
}
}
}
同步异步最终的拦截器链
可以看到,不管是同步还是异步真正的Response在getResponseWithInterceptorChain
里得到。
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
//1、OkHttpClient配置的,观察整个请求过程的拦截器
interceptors.addAll(client.interceptors());
//2、用于重连和重定向的拦截器
interceptors.add(retryAndFollowUpInterceptor);
//3、负责把用户构造的请求转换为发送到服务器的请求、
//把服务器返回的响应转换为用户友好的响应的拦截器
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//4、读取缓存直接返回、更新缓存的拦截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//5、负责和服务器建立连接的拦截器
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//6、配置OKHttpClient时设置的拦截器
interceptors.addAll(client.networkInterceptors());
}
//7、负责向服务器发送请求数据,并且读取响应数据的拦截器
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
getResponseWithInterceptorChain方法构建了一条完整的拦截器链,按照顺序执行各自的功能。这就是典型的责任链模式,每个处理对象决定它能处理哪些命令对象,然后将它不能处理的命令对象传递给链中的下一个处理对象。
这里借用一张资料图来理解整个流程,来源为:
http://blog.youkuaiyun.com/mwq384807683/article/details/71173442?locationNum=8&fps=1