okhttp调用流程分析
Android 在6.0之后也将内部的HttpUrlConnection的默认实现替换成了OkHttp
简单调用
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("https://www.google.com").build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
步骤分析(上述为异步过程分析)
观察调用流程,分析主要类
1、OkHttpClient:核心类,构建者模式实现,相当于访问门户
2、RealCall:负责请求调度,Call的实现类,同步异步请求都是它实现,其中AsyncCall是它的内部类,五大内部拦截器也在这儿被调用,通过责任链模式组织了拦截器的使用
3、Dispatcher:封装了关于何时执行异步请求的策略,并设置了最大请求数setMaxRequests(int maxRequests),可配置,每个调度程序都使用线程池来完成该任务
4、TheadPoolExecutor:线程池,为任务执行时原动力
一、分析OkHttpClient(专用于发送http请求,并接收返回的一个类)
每个客户端都拥有自己的连接池和线程池。 重用连接和线程可减少延迟并节省内存。 相反,为每个请求创建一个客户端会浪费空闲池上的资源,OkHttpClients should be shared,所以请使用单例模式
OkHttp 还使用守护线程进行 HTTP/2 连接,如果它们保持空闲,它们将自动退出
OkHttpClient默认构造器参数如下:
OkHttpClient client = new OkHttpClient();
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
if (proxySelector == null) {
proxySelector = new NullProxySelector();
}
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
callTimeout = 0;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
采用的是构建者模式,独立,易扩展,对于参数较多的构造器,比较方便,可以选择想要使用的功能,其余可默认,缺点就是通过内部静态类实现,需要有共同的参数,使用范围有限制,而且如果需求变化多端,就需要不同的构造器实现
二、RealCall
Call call = client.newCall(request);
…
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
主要是把调用放入到eventListener中以此来监听,指标事件的监听器, 扩展此类可用于监视应用程序 HTTP 调用的数量、大小和持续时间,包括(网络请求次数、流量大小、DNS解析时间、请求、响应时间等)
call.enqueue();
@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));
}
// Guarded by this.
executed:用于判断当前请求有无被执行,且只能被执行一次
captureCallStackTrace():捕获执行此方法时的堆栈信息,也就是获取Throwable中的信息,用于RetryAndFollowUpInterceptor,从故障中恢复并根据需要遵循重定向
client.dispatcher().enqueue(new AsyncCall(responseCallback)):AsyncCall是RealCall的一个非静态内部类,并且是个Runnable类,Dispatcher将runnable放入了readyAsyncCalls中,按照它们将运行的顺序准备好异步调用 (先看下面的三、Dispatcher如何进行调度)
asyncCallTask:
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
eventListener.callFailed(RealCall.this, ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
**executorService.execute(this);**内部封装线程池,其实现类为ThreadPoolExecutor,先看execute调用,实际调用的是RealCall本身的execute()方法
@Override protected void execute() {
boolean signalledCallback = false;
timeout.enter();
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) {
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 {
client.dispatcher().finished(this);
}
}
**Response response = getResponseWithInterceptorChain();**经过各种拦截器后将结果返回,其中包括
失败和重定向拦截器---------------retryAndFollowUpInterceptor
封装request和response拦截器-------BridgeInterceptor
缓存相关的过滤器负责读取缓存直接返回、更新缓存------CacheInterceptor
连接服务,负责和服务器建立连接拦截器-------ConnectInterceptor
具体执行流操作(写出请求体、获得响应数据) 负责向服务器发送请求数据、从服务器读取响应数据、进行http请求报文的封装与请求报文的解析------------CallServerInterceptor
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
分别将返回后的结果判断后回调返回,根据retryAndFollowUpInterceptor.isCanceled()判断,在任务被取消或者异步超时时会被设置为true
三、Dispatcher
client.dispatcher().enqueue(new AsyncCall(responseCallback));
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
}
promoteAndExecute();
}
将call加入到readyAsyncCalls中,一个支持两端元素插入和移除的线性集合,也就是队列结构,实现类是数组形式
promoteAndExecute():将符合条件的调用从 {@link #readyAsyncCalls} 提升到 {@link #runningAsyncCalls} 并在执行程序服务上运行它们。 不得与同步调用,因为执行调用可以调用用户代码
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
i.remove();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
asyncCall.executeOn(executorService());
}
return isRunning;
}
**assert (!Thread.holdsLock(this));**用于断言观察线程是否持有当前对象的锁,为了保证在执行下面的代码时是未上锁的
if (runningAsyncCalls.size() >= maxRequests) break; 判断异步运行中的请求的最大队列数量,默认值为64,表示能够同时运行的最大调用数量为64
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; 最大请求的host数量为5个,即共享主机的正在运行的调用数最大数量为5
综合上述这两种判断,将符合条件的调用从准备队列中移除 i.remove(),并将其加入到executableCalls与runningAsyncCalls中,其中executableCalls相当于一个暂存区,用于迭代执行其中保存的异步任务
**asyncCall.executeOn(executorService());**将异步任务加入线程池中执行,跳转到RealCall中的asyncCallTask标签
goto asyncCallTask;