OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder().build();
Call newCall = okHttpClient.newCall(request);
//同步请求
//Response response = newCall.execute();
//异步请求
newCall.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
复制代码
public Response execute() throws IOException {
synchronized (this) {
//判断当前call是否执行过,是的话抛异常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
//将当前call添加到Dispatcher正在执行的任务队列
client.dispatcher().executed(this);
//经过一系列拦截器链作网络请求,拿到response
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
//从正在执行的任务队列中移除当前call
client.dispatcher().finished(this);
}
}
复制代码
> RealCall类enqueue()方法
public void enqueue(Callback responseCallback) {
synchronized (this) {
//判断当前call是否执行过,是的话抛异常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
复制代码
判断当前call是否执行过,是的话抛异常缓存
将callBack封装成一个AsyncCall对象bash
> AsyncCall类execute()方法具体实现
protected void execute() {
boolean signalledCallback = false;
try {
//经过一系列拦截器链作网络请求,拿到response
Response response = getResponseWithInterceptorChain();
//经过判断重定向重试拦截器是否被取消了,是的话就调用responseCallback.onFailure()
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 {
//发生异常也会调用失败回调
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
//将当前请求call对象从正在运行任务队列中移除
client.dispatcher().finished(this);
}
}
复制代码
调用client.dispatcher().enqueue()服务器
> Dispatcher类enqueue()方法
//判断正在运行异步任务队列大小是否小于最大请求数(64)而且经过runningCallsForHost()方法获取到正在运行的异步任务队列中和当前call所要请求的主机同样的调用数来判断是否小于最大请求主机数(5)
//若是知足上述条件 则将当前call添加到正在运行异步任务队列中,不然添加到等待异步任务队列
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
//添加到异步任务队列
runningAsyncCalls.add(call);
//开启线程池执行当前call
//executorService()方法内部会判断线程池是否已经建立,是的话直接返回,否的话建立线程池
//execute() 未来某个时候执行给定的任务,任务能够在新线程或现有池中已存在的线程执行
//其实就是把AsyncCall(线程的实现类)对象放到线程池中,最后真正执行的就是AsyncCall对象的execute()方法
executorService().execute(call);
} else {
//添加到异步等待任务队列
readyAsyncCalls.add(call);
}
}
复制代码
什么是Dispatcher?网络
dispatcher的做用是维护请求的状态,并维护一个线程池,用于执行请求异步
Dispatcher的异步请求为何要维护两个任务队列?ide
Dispatcher 生产者ui
ExecutorService 消费者池this
executorService()spa
public synchronized ExecutorService executorService() {
if (executorService == null) {
//corePoolSize:0 核心线程数.0的话就表示在空闲一段时间(keepAliveTime)后,会将所有线程销毁
//maximumPoolSize:Integer.MAX_VALUE 线程池容许建立最大线程数;理论上设置MAX_VALUE能够无限扩充建立线程,因为OKHttp有maxRequests(64)限制,实际并不能无限建立线程
//keepAliveTime:60 空闲线程最大存活时间.当咱们的线程数大于核心线程数,多余的空闲线程最大存活时间
//3个参数含义:当线程池中任务执行完毕以后,会在60秒以后相继关闭全部空闲线程
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
复制代码
移除任务call线程
同步请求和异步请求在拿到Response以后都会调用finished()方法
> 如下方法全是在Dispatcher类中
//异步请求
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
//同步请求
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
//从当前任务队列中移除当前call
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
//调整异步请求任务队列 只有异步请求才会执行promoteCalls()
if (promoteCalls) promoteCalls();
//从新计算正在执行任务数:异步请求+同步请求任务数量之和
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
/**
异步请求队列从新调度.从等待队列中移除一个任务,添加到正在执行异步队列中
*/
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
//若是正在执行异步队列中数量大于等于最大请求数(64),直接结束调度
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
复制代码
拦截器是OkHttp中提供一种强大机制,它能够实现网络监听、请求以及响应重写、请求失败重试等功能
RetryAndFollowUpInterceptor
重试,失败重定向拦截器
BridgeInterceptor
桥接适配拦截器,处理请求缺乏必要的http请求头相关信息
CacheInterceptor
缓存拦截器,经过DiskLRUCache实现缓存存取,OkHttp内部维护清理线程池,会自动清理缓存文件
ConnectInterceptor
链接拦截器,创建可用的链接
newStream()总结
CallServerInterceptor