OkHttp流程分析,Android社招面试题

} else {
// 此处是请求失败回调
responseCallback.onFailure(RealCall.this, e);
}
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
IOException canceledException = new IOException("canceled due to " + t);
canceledException.addSuppressed(t);
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
client.dispatcher().finished(this);
}
}

在上面这个方法中我们可以看到请求的结果是如何获得,那么这个runnable任务是怎么调度执行的呢?我们就得回过头看看Dispatcher类的enqueue()方法做了啥

void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);

if (!call.get().forWebSocket) {
//如果有请求同一host的AsyncCall就进行复用
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
推动执行方法
promoteAndExecute();
}

private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));

List executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
//循环收集可以执行的AsyncCall
for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();

if (runningAsyncCalls.size() >= maxRequests) break; // 最大执行的call大于64 跳出
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // 请求同一host的call > 5 跳过

i.remove();
asyncCall.callsPerHost().incrementAndGet();
executableCalls.add(asyncCall);
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}

//把可以执行的AsyncCall,统统执行
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//executorService()返回一个线程池
asyncCall.executeOn(executorService());
}

return isRunning;
}

void executeOn(ExecutorService executorService) {
boolean success = false;
try {
//线程池运行Runnable,执行run,调用前面提到的AsyncCall.execute
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException(“executor rejected”);
ioException.initCause(e);
transmitter.noMoreExchanges(ioException);
//失败回调
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
//结束
client.dispatcher().finished(this);
}
}
}

到了这里我们的AsyncCall就顺利执行了。整个Okhttp代码的主干就在这里。接下来我们继续探讨okhttp这个框架的一些细节设计

拦截器链

前边得到Response的地方,我们调用了getResponseWithInterceptorChain()。但没细讲,这个部分就是大名鼎鼎的okhttp的拦截器链。

//RealCall.java
Response getResponseWithInterceptorChain() throws IOException {
List interceptors = new ArrayList<>();
//添加自定义拦截器
interceptors.addAll(client.interceptors());
//添加默认拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//添加自定义网络拦截器(在ConnectInterceptor后面,此时网络连接已准备好)
interceptors.addAll(client.networkInterceptors());
}
//添加默认拦截器,共4+1=5个
interceptors.add(new CallServerInterceptor(forWebSocket));
//创建拦截器链
Interceptor.Chain chain =
new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//放行
Response response = chain.proceed(originalRequest);
return response;
}

我们跟进proceed方法

Response proceed(Request request, Transmitter transmitter,Exchange exchange)
throws IOException {
//传入index + 1,可以访问下一个拦截器
RealInterceptorChain next =
new RealInterceptorChain(interceptors, transmitter, exchange,
index + 1, request, call, connectTimeout,
readTimeout, writeTimeout);
Interceptor interceptor = interceptors.get(index);
//执行第一个拦截器,同时传入next
Response response = interceptor.intercept(next);
//等所有拦截器处理完,就能返回R
esponse了
return response;
}

然后简单介绍一下各个拦截器的作用

  • RetryAndFollowUpInterceptor :负责重定向和重试
  • BridgeInterceptor :负责把应用请求变成网络请求,把网络响应变成应用响应
  • CacheInterceptor :负责okio读写缓存
  • ConnectInterceptor : 负责创建连接
  • CallServerInterceptor :负责写请求和读响应

缓存

缓存的实现是基于请求和响应的header来做的。CacheStrategy即缓存策略,CacheInterceptor拦截器会根据他拿到网络请求networkRequest、缓存响应cacheResponse,从而决定是使用网络还是缓存。由于是根据请求和响应的header来做。所以要想使用okhttp来做缓存的话。需要公司的后台同学配合。

连接池

我们先看到Transmitter这个类,Transmitter意为发射器,功能挺杂。注释说是OkHttp的应用程序和网络层之间的桥梁。newRealCall方法中有用到。我们走近这个类。Transmitter中我们可以看到RealConnectionPool 这个类。这个类就是我们的连接池了。

//RealConnectionPool.java
//线程池,用于清理过期的连接。一个连接池最多运行一个线程
Executor executor =
new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,
new SynchronousQueue<>(),
Util.threadFactory(“OkHttp ConnectionPool”, true));
//每个ip地址的最大空闲连接数,为5个
int maxIdleConnections;
//空闲连接存活时间,为5分钟
long keepAliveDurationNs;
//连接队列
Deque connections = new ArrayDeque<>();

//获取连接
boolean transmitterAcquirePooledConnection(Address address, Transmitter transmitter,
List routes, boolean requireMultiplexed) {
for (RealConnection connection : connections) {
//要求多路复用,跳过不支持多路复用的连接
if (requireMultiplexed && !connection.isMultiplexed()) continue;
//不合条件,跳过
if (!connection.isEligible(address, routes)) continue;
//分配一个连接
transmitter.acquireConnectionNoEvents(connection);
return true;
}
return false;
}

//移除连接,executor运行cleanupRunnable,调用了该方法
long cleanup(long now) {
//查找移除的连接,或下一次移除的时间
synchronized (this) {
for (Iterator i = connections.iterator(); i.hasNext(); ) {
//…
if (idleDurationNs > longestIdleDurationNs) {
longestIdleDurationNs = idleDurationNs;
longestIdleConnection = connection;
}
}
if (longestIdleDurationNs >= this.keepAliveDurationNs
); ) {
//…
if (idleDurationNs > longestIdleDurationNs) {
longestIdleDurationNs = idleDurationNs;
longestIdleConnection = connection;
}
}
if (longestIdleDurationNs >= this.keepAliveDurationNs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值