Okhttp 基本使用流程
-
1、创建okhttpClient
-
OkHttpClient ok=new OkHttpClient.Builder().build();
-
-
2 、创建Request请求
-
Request request=new Request.Builder().build();
-
-
3、创建创建Call对象 Call 是个接口 实际是通过其实现类RealCall 得到的call
-
Call call=ok.newCall(request);
-
这里的newCall 内部实际是创建的RealCall 所以后面分析同步异步的方法都在这个类里
-
@Override public Call newCall(Request request) { return RealCall.newRealCall(this, request, false /* for web socket */); }
-
-
-
4、调用
-
同步
-
call.execute();
-
-
异步
-
call.enqueue();
-
-
okHttp的Dispatcher调度过程分析
Okhttp的Dispatcher是什么
- Dispatcher 是
okhttp
给我们提供的执行异步请求时的策略
. 简单理解就是负责调度网络请求的
Dispatcher 在哪里初始化里面又包含什么
-
Dispatcher是在创建okHttpclient的时候创建的在builder里
-
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory { public static final class Builder { Dispatcher dispatcher; public Builder() { dispatcher = new Dispatcher(); /// } Builder(OkHttpClient okHttpClient) { this.dispatcher = okHttpClient.dispatcher; } }
-
-
DIspatcher 内部用什么来维护请求调度策略
-
int maxRequests = 64; //同时执行的最大请求数,可通过setMaxRequests设置
-
Runnable idleCallback;// 空闲回调
-
int maxRequestsPerHost = 5;// 同主机最大同时请求数,可通过setMaxRequestsPerHost设置
-
ExecutorService executorService;// 执行异步任务的线程池 其参数 核心线程数为0,最大线程数为Integer.MAX_VALUE ,空闲等待时间 60s 核心数为0 代表空闲时间一过线程清空
-
Deque<AsyncCall> readyAsyncCalls;// 异步任务就绪队列
-
Deque<AsyncCall> runningAsyncCalls;//异步任务执行队列
-
Deque<AsyncCall> runningAsyncCalls;//同步任务队列
-
Dispatcher 就是通过上述的队列以及线程池维护的任务调度
-
接下来分析Dispatcher 如何调度
- 根据上述我们都知道Okhttp请求分为异步和同步所以调度我们区分两种来分析
- 同步
- 异步
同步 Dispatcher 如何调度
-
okhttp执行同步请求是通过
call.execute()
,直接看execute的代码-
@Override public Response execute() throws IOException { synchronized (this) { // 1. 检测call 是否执行过 执行过就抛出异常 “已经执行” if (executed) throw new IllegalStateException("Already Executed"); executed = true; } try { //2. 这里dispatcher 将 任务ececuted 到 client.dispatcher().executed(this); Response result = getResponseWithInterceptorChain(); ///··· } catch (IOException e) { ///``` } finally { ///3 任务执行结束 通过Dispatcher finished掉 client.dispatcher().finished(this); } }
-
上面 2 处注释 dispatcher 调用 executed(this); 将任务放到同步队列中 我们看executed方法
-
synchronized void executed(RealCall call) { // 将call 对象加入同步队列 runningSyncCalls.add(call); }
-
-
注释 3 处 当任务结束时调用了Finished 方法结束 当前call 我们看起内部如何实现
-
private <T> void finished(Deque<T> calls, T call) { Runnable idleCallback; synchronized (this) { // 1、移除当前传递进来的Call 任务 if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!"); // 2 设置空闲回调 idleCallback = this.idleCallback; } // 3 这里只对异步任务有作用 boolean isRunning = promoteAndExecute(); if (!isRunning && idleCallback != null) { idleCallback.run(); } }
-
-
-
同步调度总结
- Dispatcher 调用Execute 将Call 加入 同步队列
- 任务执行结束 调用finished 将Call 从同步队列移除
异步 Dispatcher 如何调用
-
okhttp执行同步请求是通过
call.enqueue()
,直接看enqueue的代码-
@Override public void enqueue(Callback responseCallback) { synchronized (this) { // 1 检测call 是否执行过 执行过就抛出异常 “已经执行” if (executed) throw new IllegalStateException("Already Executed"); executed = true; } // 2 调用enqueue 传入一个AsynvCall 其实是个Runnable 所以需要线程池调用 client.dispatcher().enqueue(new AsyncCall(responseCallback)); }
-
-
上面 2 处注释 dispatcher 调用 enqueue 将任务放到同步队列中 我们看enqueue方法
-
void enqueue(AsyncCall call) { synchronized (this) { // 1 将Async call 加入等待就绪队列 readyAsyncCalls.add(call); } // 2 调用促进执行 将符合条件的加入到RunningAsyncCalls 中 promoteAndExecute(); }
-
private boolean promoteAndExecute() { assert (!Thread.holdsLock(this)); List<AsyncCall> executableCalls = new ArrayList<>(); boolean isRunning; synchronized (this) { // for 循环遍历realAsyncCalls 判断asyncCall判断是否满足加入 // RunningAsyncCall 若满足 则将其从realAsyncCalls中移除 //并加入RunningAsyncCalls for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) { // 1 获取AsyncCall AsyncCall asyncCall = i.next(); // 2 判断runningAsyncCalls 是否超出最大线程数 不是向下执行 是直接跳出 if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity. // 3 判断callsPerHost同一主机请求数数量否超出 不是向下执行 是跳过选择下一个 if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity. i.remove();// 4 在realAsyncCalls中移除该AsyncCall asyncCall.callsPerHost().incrementAndGet(); // 5 加入可执行调用队列 executableCalls.add(asyncCall); // 6 将asyncCall 加入运行队列 runningAsyncCalls runningAsyncCalls.add(asyncCall); } isRunning = runningCallsCount() > 0; } for (int i = 0, size = executableCalls.size(); i < size; i++) { // 7 从可执行调用队列中取出async Call AsyncCall asyncCall = executableCalls.get(i); // 8 调用asyncCall 的ExecutOn方法传递线程池 asyncCall.executeOn(executorService()); } return isRunning; }
-
void executeOn(ExecutorService executorService) { assert (!Thread.holdsLock(client.dispatcher())); boolean success = false; try { //9 通过线程池执行Runnable->AsyncCall // AsyncCall 是继承自 NamedRunnable 内部run方法中调用了execute() // 所以我们看execute中做了什么 如下 executorService.execute(this); } catch (RejectedExecutionException e) { } finally { if (!success) { client.dispatcher().finished(this); // This call is no longer running! } } }
-
@Override protected void execute() { boolean signalledCallback = false; timeout.enter(); try { // 10 通过链式调用 获取response Response response = getResponseWithInterceptorChain(); // 没取消则响应onResponse 否则响应onFailure if (retryAndFollowUpInterceptor.isCanceled()) { signalledCallback = true; responseCallback.onFailure(RealCall.this, new IOException("Canceled")); } else { signalledCallback = true; responseCallback.onResponse(RealCall.this, response); } } catch (IOException e) { e = timeoutExit(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 { // 11 dispatcher 调用 finished 方法 client.dispatcher().finished(this); } } }
-
private <T> void finished(Deque<T> calls, T call) { Runnable idleCallback; synchronized (this) { // 12 在运行队列中移除该call if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!"); idleCallback = this.idleCallback; } // 13 执行promoteAndExecute 再次将可执行的AsyncCall 添加到运行队列 boolean isRunning = promoteAndExecute(); if (!isRunning && idleCallback != null) { idleCallback.run(); } }
-
异步调度总结
- 1、Dispatcher 调用 enqueue 将AsyncCall 加入 RealAsyncCalls 等待队列
- 2 、调用 promoteAndExecute() 方法 for 循环从realAsyncCalls 中取出 AsyncCall 并判断是否满足加入RunningAsyncCalls的条件
- 不超过最大线程数
- 不超过最大主机同时访问数
- 若满足 则添加到RunnAsyncCalls中 不满足则跳过判断下一个AsyncCall
- 3 、从RunnAsyncCalls取出AsyncCall 调用其executeOn方法将线程池传入
- 4 、线程池executorService通过execute(this)执行当前AsyncCall
- (AsyncCall 是继承自 NamedRunnable 内部run方法中调用了execute() 所以实现在execute中)
- 5、在execute方法中 通过责任链执行网络请求获取Response
- 6、 执行结束 dispatcher 调用finished方法 从RunningAsyncCalls中移除当前AsyncCall ,并调用第二步骤的promoteAndExecute()方法 判断是否有可执行AsyncCall
- 若有则继续执行
- 若没有则返回false 并触发空闲回调
- 这就是异步调用的过程分析了