本文使用的okhttp版本是:2.7.5
compile group: 'com.squareup.okhttp', name: 'okhttp', version: '2.7.5'
简单使用
使用okhttp发送一个网络请求是十分的方便的
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url("").build();//建造者设计模式
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
//请求失败的回调
}
@Override
public void onResponse(Response response) throws IOException {
//请求成功的回调
}
});
源码解读
先看一下call.enqueue()做了啥
public void enqueue(Callback responseCallback) {
enqueue(responseCallback, false);
}
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {//加同步锁
//如果已经执行过了,就抛异常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//这里的client就是okHttpClient,这里调用了okhttclient中的dispatcher的enqueue方法,new AsyncCall(responseCallback, forWebSocket)是对responseCallback的二次封装
client.getDispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
继续看下enqueue(),runningCalls、readyCalls都是ArrayDeque(循环队列),runningCalls存储是正在执行中的AsyncCall,readyCalls存储的是将要执行的AsyncCall。
synchronized void enqueue(AsyncCall call) {
//runningCalls、readyCalls都是ArrayDeque(循环队列),runningCalls存储是正在执行中的AsyncCall,readyCalls存储的是将要执行的AsyncCall。
if (runningCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//加入到运行队列中
runningCalls.add(call);
//直接利用线程池去执行这个AsyncCall
getExecutorService().execute(call);
} else {
//加入到等待队列中
readyCalls.add(call);
}
}
看下ExecutorService (),注意这里的创建了一个线程池,线程池的核心线程数量为0,最大线程数量为Integer.MAX_VALUE,空闲超时时间为60秒,SynchronousQueue是一个无容量的等待队列。这个线程池的作用是:只要有任务来,就马上利用空闲的线程或者创建新线程去执行任务,线程的空闲时间超过60秒就会被撤销收回。(其实是一个可缓存线程池,将每一个空闲的线程都缓存60秒)
public synchronized ExecutorService getExecutorService() {
if (executorService == null) {
//创建了一个线程池,线程池的核心线程数量为0,最大线程数量为Integer.MAX_VALUE,空闲超时时间为60秒,SynchronousQueue是一个无容量的等待队列。这个线程池的作用是:只要有任务来,就马上利用空闲的线程或者创建新线程去执行任务,线程的空闲时间超过60秒就会被撤销收回。(其实是一个可缓存线程池)
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
getExecutorService().execute(call),这句代码线程池会执行call中的run方法,所以看一下AsyncCall的父类NamedRunnable中的run函数
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
//就是说,线程池最终会执行execute()
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
//受保护的抽象方法
protected abstract void execute();
看一下AsyncCall中execute()的具体实现,其实就是getResponseWithInterceptorChain函数去执行责任链中的每一个拦截器中的处理代码
@Override protected void execute() {
boolean signalledCallback = false;
try {
//核心代码,开始执行责任链中的每个拦截器的拦截代码
Response response = getResponseWithInterceptorChain(forWebSocket);
if (canceled) {
signalledCallback = true;
//执行失败则回调onFailure
responseCallback.onFailure(originalRequest, new IOException("Canceled"));
} else {
signalledCallback = true;
//执行成功则回调onResponse
responseCallback.onResponse(response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
logger.log(Level.INFO, "Callback failure for " + toLoggableString(), e);
} else {
Request request = engine == null ? originalRequest : engine.getRequest();
responseCallback.onFailure(request, e);
}
} finally {
//执行下一个call
client.getDispatcher().finished(this);
}
}
getResponseWithInterceptorChain函数
private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
return chain.proceed(originalRequest);
}
ApplicationInterceptorChain 是啥?细细一看,这就是大名鼎鼎的责任链设计模式了,等责任链中的拦截器都处理完之后,发送http请求并将相应结果返回。
class ApplicationInterceptorChain implements Interceptor.Chain {
//执行到的节点下标
private final int index;
private final Request request;
private final boolean forWebSocket;
ApplicationInterceptorChain(int index, Request request, boolean forWebSocket) {
this.index = index;
this.request = request;
this.forWebSocket = forWebSocket;
}
@Override public Connection connection() {
return null;
}
@Override public Request request() {
return request;
}
//责任链中的核心代码,执行链条中每个节点(拦截器)的业务
@Override public Response proceed(Request request) throws IOException {
// If there's another interceptor in the chain, call that.
//获取拦截器
if (index < client.interceptors().size()) {
Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
//得到链条中当前下标对应的拦截器
Interceptor interceptor = client.interceptors().get(index);
//执行拦截器中的拦截事件
Response interceptedResponse = interceptor.intercept(chain);
if (interceptedResponse == null) {
throw new NullPointerException("application interceptor " + interceptor
+ " returned null");
}
return interceptedResponse;
}
// No more interceptors. Do HTTP.
//责任链中的拦截器都处理完之后,发送http请求并将相应结果返回
return getResponse(request, forWebSocket);
}
}
finished(),因为这个时候是已经执行完了call,所以这个函数作用是可以把call从运行队列runningCalls中移除,然后调用promoteCalls()去执行下一批call
synchronized void finished(AsyncCall call) {
//因为这个时候是已经执行完了call,所以可以把call从运行队列runningCalls中移除了
if (!runningCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
promoteCalls();
}
调用promoteCalls,又开始用线程池去执行等待队列readyCalls中的网络请求任务call。其实就是遍历等待readyCalls中的每一个任务,用线程池去执行每一个call,并且将call加入到运行队列中,同时将该call从等待readCalls中删除。
private void promoteCalls() {
if (runningCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyCalls.isEmpty()) return; // No ready calls to promote.
//遍历等待readyCalls中的每一个任务,用线程池去执行每一个call,并且将call加入到运行队列中,同时将该call从等待readCalls中删除。
for (Iterator<AsyncCall> i = readyCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningCalls.add(call);
getExecutorService().execute(call);
}
if (runningCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
源码解读结束
总结
okhttp其实就是把一个一个的网络请求封装成了一个一个的AsyncCall对象,AsyncCall中包含了请求url、请求内容还有用户自定好的请求失败或者成功之后的回调。okhttp同时维护了两个队列,一个是等待队列readyCalls、一个是runningCalls。在加入一个新的AsyncCall的时候,判断runningCalls中的任务数是否小于maxRequests(默认是64)并且runningCalls是否小于maxRequestsPerHost(默认是5),如果成立的话,就把AsyncCall加入到runningCalls,并且用一个可缓存线程池去执行这个任务;如果不成立的话,会把AsyncCall加入到等待队列readyCalls中。AsyncCall被执行的过程是:可缓存线程池会去执行AsyncCall中的execute函数,execute函数中就会启动一个责任链,责任链就会去执行okhttpclient中的每一个拦截器的处理代码,最后发送http请求并将结果返回,然后回调AsyncCall中的onFailure或者onResponse方法。回调完之后把运行队列runningCalls的已经执行结束的call给删除掉,然后继续遍历等待队列readyCalls,用可缓存线程池去执行其中的每一个call。