OkHttp源码分析
1、基本使用
// to create a shared instance with the custom settings
// 共享client实例
public final OkHttpClient client = new OkHttpClient.Builder()
// 设置拦截器
.addInterceptor(new HttpLoggingInterceptor())
// 设置缓存路径以及缓存大小
.cache(new Cache(cacheDir, cacheSize))
.build();
// You can customize a shared OkHttpClient instance with {@link #newBuilder()}. This builds a client that shares the same connection pool, thread pools, and configuration. Use the buildermethods to configure the derived client for a specific purpose.
// 共享client连接池、线程池和配置
public final OkHttpClient client = new OkHttpClient();
OkHttpClient eagerClient = client.newBuilder()
// 设置读取时间
.readTimeout(500, TimeUnit.MILLISECONDS)
.build();
Response response = eagerClient.newCall(request).execute();
// 关闭executorService
client.dispatcher().executorService().shutdown();
// 清空连接池
client.connectionPool().evictAll();
// 关闭缓存,如果已经设置了缓存,会导致请求call崩溃
client.cache().close();
使用client.newBuilder()方式会共享client的相同的连接池、线程池和参数配置,使用new OkHttpClient.Builder()会共享创建的client实例
2、源码分析
首先分析共享client的方式
new OkHttpClient.Builder()
public Builder() {
// 异步请求执行政策
dispatcher = new Dispatcher();
// http协议
protocols = DEFAULT_PROTOCOLS;
// 默认连接规格
connectionSpecs = DEFAULT_CONNECTION_SPECS;
// 事件监听工厂
eventListenerFactory = EventListener.factory(EventListener.NONE);
// 代理选择器
proxySelector = ProxySelector.getDefault();
// cookie设置
cookieJar = CookieJar.NO_COOKIES;
// socket工厂
socketFactory = SocketFactory.getDefault();
// 主机名认证
hostnameVerifier = OkHostnameVerifier.INSTANCE;
// 证书pinner
certificatePinner = CertificatePinner.DEFAULT;
// 代理身份认证
proxyAuthenticator = Authenticator.NONE;
// 身份认证
authenticator = Authenticator.NONE;
// 连接池
connectionPool = new ConnectionPool();
// DNS
dns = Dns.SYSTEM;
// 遵循SSL重定向
followSslRedirects = true;
// 遵循重定向
followRedirects = true;
// 连接失败重试
retryOnConnectionFailure = true;
// 连接超时时间
connectTimeout = 10_000;
// 读取超时使劲
readTimeout = 10_000;
// 写入超时时间
writeTimeout = 10_000;
// ping时间间隔
pingInterval = 0;
}
addInterceptor(new HttpLoggingInterceptor())
/**
* Returns a modifiable list of interceptors that observe the full span of each call: from
* before the connection is established (if any) until after the response source is selected
* (either the origin server, cache, or both).
*/
// 返回可修改的interceptor集合,interceptor用于观察从established之前到响应资源的全过程,内容包括原始服务器、缓存或者两者都包括
public List<Interceptor> interceptors() {
return interceptors;
}
public Builder addInterceptor(Interceptor interceptor) {
if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
interceptors.add(interceptor);
return this;
}
/**
* Returns a modifiable list of interceptors that observe a single network request and response.
* These interceptors must call {@link Interceptor.Chain#proceed} exactly once: it is an error
* for a network interceptor to short-circuit or repeat a network request.
*/
// 观察单独的一次请求和响应,对于短路和重复请求会报错
public List<Interceptor> networkInterceptors() {
return networkInterceptors;
}
public Builder addNetworkInterceptor(Interceptor interceptor) {
if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
networkInterceptors.add(interceptor);
return this;
}
interceptor和netWorkInterceptor区别
addInterceptor() 添加应用拦截器
不需要担心中间过程的响应,如重定向和重试.
总是只调用一次,即使HTTP响应是从缓存中获取.
观察应用程序的初衷. 不关心OkHttp注入的头信息如: If-None-Match.
允许短路而不调用 Chain.proceed(),即中止调用.
允许重试,使 Chain.proceed()调用多次.
addNetworkInterceptor() 添加网络拦截器
能够操作中间过程的响应,如重定向和重试.
当网络短路而返回缓存响应时不被调用.
只观察在网络上传输的数据.
携带请求来访问连接.
.cache
// 设置响应缓存,用于读写缓存响应数据
/** Sets the response cache to be used to read and write cached responses. */
public Builder cache(@Nullable Cache cache) {
this.cache = cache;
this.internalCache = null;
return this;
}
查看Cache类基本使用
方式一:设置无缓存
Request request = new Request.Builder()
.cacheControl(new CacheControl.Builder().noCache().build())
.url("http://publicobject.com/helloworld.txt")
.build();
方式二:设置具有超时时间的缓存
Request request = new Request.Builder()
.cacheControl(new CacheControl.Builder()
.maxAge(0, TimeUnit.SECONDS)
.build())
.url("http://publicobject.com/helloworld.txt")
.build();
方式三:设置只读取缓存内容
Request request = new Request.Builder()
.cacheControl(new CacheControl.Builder()
.onlyIfCached()
.build())
.url("http://publicobject.com/helloworld.txt")
.build();
// 可以根据forceCacheResponse.code()设置是否读取缓存
Response forceCacheResponse = client.newCall(request).execute();
if (forceCacheResponse.code() != 504) {
// The resource was cached! Show it.
} else {
// The resource was not cached.
}
方式四:设置缓存时间为365天
Request request = new Request.Builder()
.cacheControl(new CacheControl.Builder()
.maxStale(365, TimeUnit.DAYS)
.build())
.url("http://publicobject.com/helloworld.txt")
.build();
}
构造方法分析
// 指定文件目录和缓存大小
public Cache(File directory, long maxSize) {
this(directory, maxSize, FileSystem.SYSTEM);
}
// 通过DiskLruCache.create()方法缓存至磁盘
Cache(File directory, long maxSize, FileSystem fileSystem) {
this.cache = DiskLruCache.create(fileSystem, directory, VERSION, ENTRY_COUNT, maxSize);
}
跟进DiskLruCache.create方法
/**
* Create a cache which will reside in {@code directory}. This cache is lazily initialized on
* first access and will be created if it does not exist.
*
* @param directory a writable directory
* @param valueCount the number of values per cache entry. Must be positive.
* @param maxSize the maximum number of bytes this cache should use to store
*/
public static DiskLruCache create(FileSystem fileSystem, File directory, int appVersion,
int valueCount, long maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
if (valueCount <= 0) {
throw new IllegalArgumentException("valueCount <= 0");
}
// Use a single background thread to evict entries.
// 使用线程池进行管理,核心线程数为0,非核心线程数为1,存活时间为30秒
Executor executor = new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(), Util.threadFactory("OkHttp DiskLruCache", true));
return new DiskLruCache(fileSystem, directory, appVersion, valueCount, maxSize, executor);
}
查看new DiskLruCache构造方法
// 构造传参
DiskLruCache(FileSystem fileSystem, File directory, int appVersion, int valueCount, long maxSize,
Executor executor) {
// fileSystem
this.fileSystem = fileSystem;
// 路径
this.directory = directory;
// app版本
this.appVersion = appVersion;
// 日志文件
this.journalFile = new File(directory, JOURNAL_FILE);
// 临时日志文件
this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP);
// 日志文件本分
this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP);
// 值数量
this.valueCount = valueCount;
// 缓存最大值
this.maxSize = maxSize;
// 线程池
this.executor = executor;
}
查看线程池Runnable
/** Used to run 'cleanupRunnable' for journal rebuilds. */
private final Runnable cleanupRunnable = new Runnable() {
public void run() {
synchronized (DiskLruCache.this) {
if (!initialized | closed) {
return; // Nothing to do
}
try {
// 削减大小
trimToSize();
} catch (IOException ignored) {
mostRecentTrimFailed = true;
}
try {
if (journalRebuildRequired()) {
// 重建Journal
rebuildJournal();
redundantOpCount = 0;
}
} catch (IOException e) {
mostRecentRebuildFailed = true;
journalWriter = Okio.buffer(Okio.blackhole());
}
}
}
};
查看trimToSize
void trimToSize() throws IOException {
while (size > maxSize) {
// final LinkedHashMap<String, Entry> lruEntries = new LinkedHashMap<>
// lruEntries 使用linkedHashMap管理缓存
Entry toEvict = lruEntries.values().iterator().next();
// 从末尾移除不常用缓存数据
removeEntry(toEvict);
}
mostRecentTrimFailed = false;
}
查看 removeEntry(toEvict);
boolean removeEntry(Entry entry) throws IOException {
if (entry.currentEditor != null) {
entry.currentEditor.detach(); // Prevent the edit from completing normally.
}
for (int i = 0; i < valueCount; i++) {
fileSystem.delete(entry.cleanFiles[i]);
// 将entry.lengths[i]从数据中移除
size -= entry.lengths[i];
entry.lengths[i] = 0;
}
// 计数器累加
redundantOpCount++;
journalWriter.writeUtf8(REMOVE).writeByte(' ').writeUtf8(entry.key).writeByte('\n');
// 从linkedHashMap中移除该键
lruEntries.remove(entry.key);
if (journalRebuildRequired()) {
// 如果需要rebuild再次调用线程池执行cleanupRunnable
executor.execute(cleanupRunnable);
}
return true;
}
查看 runnable中执行的rebuildJournal()方法
/**
* Creates a new journal that omits redundant information. This replaces the current journal if it
* exists.
*/
// 创建一个journal,去除了多余的信息,如果存在的话就是用当前的journal进行替换
synchronized void rebuildJournal() throws IOException {
if (journalWriter != null) {
journalWriter.close();
}
BufferedSink writer = Okio.buffer(fileSystem.sink(journalFileTmp));
try {
writer.writeUtf8(MAGIC).writeByte('\n');
writer.writeUtf8(VERSION_1).writeByte('\n');
writer.writeDecimalLong(appVersion).writeByte('\n');
writer.writeDecimalLong(valueCount).writeByte('\n');
writer.writeByte('\n');
for (Entry entry : lruEntries.values()) {
if (entry.currentEditor != null) {
writer.writeUtf8(DIRTY).writeByte(' ');
writer.writeUtf8(entry.key);
writer.writeByte('\n');
} else {
writer.writeUtf8(CLEAN).writeByte(' ');
writer.writeUtf8(entry.key);
entry.writeLengths(writer);
writer.writeByte('\n');
}
}
} finally {
writer.close();
}
if (fileSystem.exists(journalFile)) {
fileSystem.rename(journalFile, journalFileBackup);
}
fileSystem.rename(journalFileTmp, journalFile);
fileSystem.delete(journalFileBackup);
journalWriter = newJournalWriter();
hasJournalErrors = false;
mostRecentRebuildFailed = false;
}
build();
public OkHttpClient build() {
// 直接调用OkHttpClient构造方法构建OkHttpClient实例
return new OkHttpClient(this);
}
OkHttpClient构造
OkHttpClient(Builder builder) {
// 通过builder中各项参数设置,为创建OkHttpClient相应参数进行赋值操作
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
// 如果设置了sslSocketFactory使用设置的sslSocketFactory
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
// 使用默认的systemDefaultSslSocketFactory进行X509认证管理
X509TrustManager trustManager = systemDefaultTrustManager();
this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}
new OkHttpClient() 通过构造直接创建OkHttpClient实例
// 直接调用 this(new Builder());方法
public OkHttpClient() {
this(new Builder());
}
跟进this(new Builder());
调用了含参构造方法 OkHttpClient(Builder builder) {,同时使用匿名创建Builder对象实例
继续查看new Builder()
public Builder() {
通过调用查看类似于使用
new OkHttpClient.Builder().build()方法
client.newBuilder()
public Builder newBuilder() {
return new Builder(this);
}
查看调用,内部调用了Builder的含参构造方法将okHttpClient作为参数传递
Builder(OkHttpClient okHttpClient) {
继续跟进 new Builder(this);
Builder(OkHttpClient okHttpClient) {
this.dispatcher = okHttpClient.dispatcher;
// 代理
this.proxy = okHttpClient.proxy;
this.protocols = okHttpClient.protocols;
this.connectionSpecs = okHttpClient.connectionSpecs;
// 拦截器
this.interceptors.addAll(okHttpClient.interceptors);
// 网络拦截器
this.networkInterceptors.addAll(okHttpClient.networkInterceptors);
this.eventListenerFactory = okHttpClient.eventListenerFactory;
this.proxySelector = okHttpClient.proxySelector;
this.cookieJar = okHttpClient.cookieJar;
// 内部缓存
this.internalCache = okHttpClient.internalCache;
// 缓存
this.cache = okHttpClient.cache;
this.socketFactory = okHttpClient.socketFactory;
// ssl Scoket工厂
this.sslSocketFactory = okHttpClient.sslSocketFactory;
// 认证链cleaner
this.certificateChainCleaner = okHttpClient.certificateChainCleaner;
this.hostnameVerifier = okHttpClient.hostnameVerifier;
this.certificatePinner = okHttpClient.certificatePinner;
this.proxyAuthenticator = okHttpClient.proxyAuthenticator;
this.authenticator = okHttpClient.authenticator;
// 连接池
this.connectionPool = okHttpClient.connectionPool;
this.dns = okHttpClient.dns;
this.followSslRedirects = okHttpClient.followSslRedirects;
this.followRedirects = okHttpClient.followRedirects;
this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure;
this.connectTimeout = okHttpClient.connectTimeout;
this.readTimeout = okHttpClient.readTimeout;
this.writeTimeout = okHttpClient.writeTimeout;
this.pingInterval = okHttpClient.pingInterval;
}
通过查看Builder构造方法,对比无参构造方法,新增了缓存、拦截器赋值操作,实现共享client的相同的连接池、线程池和参数配置
readTimeout(500, TimeUnit.MILLISECONDS)
// 设置读取新连接超时时间
public Builder readTimeout(long timeout, TimeUnit unit) {
readTimeout = checkDuration("timeout", timeout, unit);
return this;
}
.build();
build方法与使用okHttpClient.Buider()方式的build相同,通过构造OkHttpClient
public OkHttpClient build() {
return new OkHttpClient(this);
}
okHttpClient.newCall(request).execute();
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
// 准备在未来的某个点执行请求操作
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
继续跟进 RealCall.newRealCall(this, request, false /* for web socket */);
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
// 安全的发布一个call实例到EventListener
// 创建realCall实例
RealCall call = new RealCall(client, originalRequest, forWebSocket);
// 创建eventListener监听
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
// 查看new RealCall(client, originalRequest, forWebSocket)调用
// 其实就是通过构造传参
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
查看client.eventListenerFactory().create(call)实现,通过传递的call实例创建EventListener
public interface Factory {
/**
* Creates an instance of the {@link EventListener} for a particular {@link Call}. The returned
* {@link EventListener} instance will be used during the lifecycle of the {@code call}.
*
* <p>This method is invoked after the {@code call} is created. See
* {@link OkHttpClient#newCall(Request)}.
*
* <p><strong>It is an error for implementations to issue any mutating operations on the
* {@code call} instance from this method.</strong>
*/
EventListener create(Call call);
}
execute();
public interface Call extends Cloneable {’
Response execute() throws IOException;
通过查看call是一个接口类型,我们要具体execute方法要查看其实现类也就是RealCall中execute()方法
RealCall中execute()方法
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
// execute标记
executed = true;
}
// 捕获调用堆栈跟踪
captureCallStackTrace();
// callStart监听
eventListener.callStart(this);
try {
// 调用okHttpClient的dispatch执行操作
client.dispatcher().executed(this);
// 通过拦截器链获取响应
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
// 回调callFailed方法
eventListener.callFailed(this, e);
throw e;
} finally {
// 结束okHttpClinet的diapatcher分发
client.dispatcher().finished(this);
}
}
查看getResponseWithInterceptorChain()实现
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
// 添加拦截器
interceptors.addAll(client.interceptors());
// 添加重试和追踪拦截器
interceptors.add(retryAndFollowUpInterceptor);
// 添加BridgeInterceptor
interceptors.add(new BridgeInterceptor(client.cookieJar()));
// 添加CacheInterceptor
interceptors.add(new CacheInterceptor(client.internalCache()));
// 添加ConnectInterceptor
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
// 通过chain的process方法获取response
return chain.proceed(originalRequest);
}
查看chain.proceed(originalRequest)实现
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
继续查看proceed方法实现
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// 省略部分代码
// Call the next interceptor in the chain.
// 创建真正的拦截器链
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
// 根据索引获取interceptor拦截器
Interceptor interceptor = interceptors.get(index);
// 通过拦截器获取响应数据
Response response = interceptor.intercept(next);
// 省略部分代码
return response;
}
// 继续查看 interceptor.intercept(next)方法实现
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
Interceptor 拦截器
BridgeInterceptor 桥梁拦截器
应用代码到网络代码的桥梁,从用户请求创建网络请求,进行网络访问,最后从网络响应购将用户响应,主要用于处理header
/**
* Bridges from application code to network code. First it builds a network request from a user
* request. Then it proceeds to call the network. Finally it builds a user response from the network
* response.
*/
public final class BridgeInterceptor implements Interceptor {
private final CookieJar cookieJar;
public BridgeInterceptor(CookieJar cookieJar) {
this.cookieJar = cookieJar;
}
@Override public Response intercept(Chain chain) throws IOException {
Request userRequest = chain.request();
Request.Builder requestBuilder = userRequest.newBuilder();
RequestBody body = userRequest.body();
if (body != null) {
MediaType contentType = body.contentType();
if (contentType != null) {
// 添加header
requestBuilder.header("Content-Type", contentType.toString());
}
long contentLength = body.contentLength();
if (contentLength != -1) {
requestBuilder.header("Content-Length", Long.toString(contentLength));
requestBuilder.removeHeader("Transfer-Encoding");
} else {
requestBuilder.header("Transfer-Encoding", "chunked");
requestBuilder.removeHeader("Content-Length");
}
}
if (userRequest.header("Host") == null) {
requestBuilder.header("Host", hostHeader(userRequest.url(), false));
}
if (userRequest.header("Connection") == null) {
requestBuilder.header("Connection", "Keep-Alive");
}
// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
transparentGzip = true;
requestBuilder.header("Accept-Encoding", "gzip");
}
// 从request强求中获取cookie
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
// 添加cookie header
requestBuilder.header("Cookie", cookieHeader(cookies));
}
if (userRequest.header("User-Agent") == null) {
// 添加version到header
requestBuilder.header("User-Agent", Version.userAgent());
}
// 获取响应response
Response networkResponse = chain.proceed(requestBuilder.build());
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
String contentType = networkResponse.header("Content-Type");
responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}
// 返回为header赋值后的responseBuilder
return responseBuilder.build();
}
/** Returns a 'Cookie' HTTP request header with all cookies, like {@code a=b; c=d}. */
// 添加CookieHeader
private String cookieHeader(List<Cookie> cookies) {
StringBuilder cookieHeader = new StringBuilder();
for (int i = 0, size = cookies.size(); i < size; i++) {
if (i > 0) {
cookieHeader.append("; ");
}
Cookie cookie = cookies.get(i);
cookieHeader.append(cookie.name()).append('=').append(cookie.value());
}
return cookieHeader.toString();
}
}
CacheInterceptor 缓存拦截器
/** Serves requests from the cache and writes responses to the cache. */
// 服务器从缓存中请求并且将响应写入缓存中
public final class CacheInterceptor implements Interceptor {
// 内部缓存
final InternalCache cache;
public CacheInterceptor(InternalCache cache) {
this.cache = cache;
}
@Override public Response intercept(Chain chain) throws IOException {
// 存在缓存,从缓存中获取,不存在缓存为null
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;
long now = System.currentTimeMillis();
// 通过缓存策略工厂获取缓存策略实例
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
// 网络请求
Request networkRequest = strategy.networkRequest;
// 缓存响应
Response cacheResponse = strategy.cacheResponse;
if (cache != null) {
//跟踪http响应
cache.trackResponse(strategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
// If we're forbidden from using the network and the cache is insufficient, fail.
//禁止使用网络或者缓存不足,失败
if (networkRequest == null && cacheResponse == null) {
return new Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(Util.EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
}
// If we don't need the network, we're done.
// 没有网络,读取缓存
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
// 通过拦截器获取网络响应
networkResponse = chain.proceed(networkRequest);
} finally {
// If we're crashing on I/O or otherwise, don't leak the cache body.
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
// If we have a cache response too, then we're doing a conditional get.
// 缓存不为空,并且响应没有发生改变
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) {
Response response = cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis())
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
// Update the cache after combining headers but before stripping the
// Content-Encoding header (as performed by initContentStream()).
cache.trackConditionalCacheHit();
// 更新缓存
cache.update(cacheResponse, response);
return response;
} else {
closeQuietly(cacheResponse.body());
}
}
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (cache != null) {
if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
// Offer this request to the cache.
// 可以缓存,并且有响应体,将响应数据放入缓存中
CacheRequest cacheRequest = cache.put(response);
return cacheWritingResponse(cacheRequest, response);
}
// 更新缓存
if (HttpMethod.invalidatesCache(networkRequest.method())) {
try {
// 移除缓存请求
cache.remove(networkRequest);
} catch (IOException ignored) {
// The cache cannot be written.
}
}
}
return response;
}
private static Response stripBody(Response response) {
return response != null && response.body() != null
? response.newBuilder().body(null).build()
: response;
}
/**
* Returns a new source that writes bytes to {@code cacheRequest} as they are read by the source
* consumer. This is careful to discard bytes left over when the stream is closed; otherwise we
* may never exhaust the source stream and therefore not complete the cached response.
*/
// 缓存写入响应
private Response cacheWritingResponse(final CacheRequest cacheRequest, Response response)
throws IOException {
// Some apps return a null body; for compatibility we treat that like a null cache request.
if (cacheRequest == null) return response;
Sink cacheBodyUnbuffered = cacheRequest.body();
if (cacheBodyUnbuffered == null) return response;
final BufferedSource source = response.body().source();
final BufferedSink cacheBody = Okio.buffer(cacheBodyUnbuffered);
Source cacheWritingSource = new Source() {
boolean cacheRequestClosed;
@Override public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead;
try {
bytesRead = source.read(sink, byteCount);
} catch (IOException e) {
if (!cacheRequestClosed) {
cacheRequestClosed = true;
cacheRequest.abort(); // Failed to write a complete cache response.
}
throw e;
}
if (bytesRead == -1) {
if (!cacheRequestClosed) {
cacheRequestClosed = true;
cacheBody.close(); // The cache response is complete!
}
return -1;
}
sink.copyTo(cacheBody.buffer(), sink.size() - bytesRead, bytesRead);
cacheBody.emitCompleteSegments();
return bytesRead;
}
@Override public Timeout timeout() {
return source.timeout();
}
@Override public void close() throws IOException {
if (!cacheRequestClosed
&& !discard(this, HttpCodec.DISCARD_STREAM_TIMEOUT_MILLIS, MILLISECONDS)) {
cacheRequestClosed = true;
cacheRequest.abort();
}
source.close();
}
};
String contentType = response.header("Content-Type");
long contentLength = response.body().contentLength();
return response.newBuilder()
.body(new RealResponseBody(contentType, contentLength, Okio.buffer(cacheWritingSource)))
.build();
}
/** Combines cached headers with a network headers as defined by RFC 7234, 4.3.4. */
// 合并headers
private static Headers combine(Headers cachedHeaders, Headers networkHeaders) {
Headers.Builder result = new Headers.Builder();
for (int i = 0, size = cachedHeaders.size(); i < size; i++) {
String fieldName = cachedHeaders.name(i);
String value = cachedHeaders.value(i);
if ("Warning".equalsIgnoreCase(fieldName) && value.startsWith("1")) {
continue; // Drop 100-level freshness warnings.
}
if (isContentSpecificHeader(fieldName) || !isEndToEnd(fieldName)
|| networkHeaders.get(fieldName) == null) {
Internal.instance.addLenient(result, fieldName, value);
}
}
// 遍历networkHeaders
for (int i = 0, size = networkHeaders.size(); i < size; i++) {
String fieldName = networkHeaders.name(i);
if (!isContentSpecificHeader(fieldName) && isEndToEnd(fieldName)) {
Internal.instance.addLenient(result, fieldName, networkHeaders.value(i));
}
}
return result.build();
}
/**
* Returns true if {@code fieldName} is an end-to-end HTTP header, as defined by RFC 2616,
* 13.5.1.
*/
static boolean isEndToEnd(String fieldName) {
return !"Connection".equalsIgnoreCase(fieldName)
&& !"Keep-Alive".equalsIgnoreCase(fieldName)
&& !"Proxy-Authenticate".equalsIgnoreCase(fieldName)
&& !"Proxy-Authorization".equalsIgnoreCase(fieldName)
&& !"TE".equalsIgnoreCase(fieldName)
&& !"Trailers".equalsIgnoreCase(fieldName)
&& !"Transfer-Encoding".equalsIgnoreCase(fieldName)
&& !"Upgrade".equalsIgnoreCase(fieldName);
}
/**
* Returns true if {@code fieldName} is content specific and therefore should always be used
* from cached headers.
*/
static boolean isContentSpecificHeader(String fieldName) {
return "Content-Length".equalsIgnoreCase(fieldName)
|| "Content-Encoding".equalsIgnoreCase(fieldName)
|| "Content-Type".equalsIgnoreCase(fieldName);
}
}
RetryAndFollowUpInterceptor 重试和重定向拦截器
主要代码
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();
EventListener eventListener = realChain.eventListener();
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
int followUpCount = 0;
Response priorResponse = null;
while (true) {
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
// 获取响应数据
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been
sent.
// RouteException 路径异常,尝试恢复
if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
throw e.getLastConnectException();
}
releaseConnection = false;
continue;
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
// 服务器通信连接失败,尝试恢复
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, streamAllocation, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
} finally {
// We're throwing an unchecked exception. Release any resources.
// 抛出未检测的异常
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
// Attach the prior response if it exists. Such responses never have a body.
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
// 重定向
Request followUp = followUpRequest(response, streamAllocation.route());
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
return response;
}
closeQuietly(response.body());
// 超过了最大重定向认证数
if (++followUpCount > MAX_FOLLOW_UPS) {
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
// 不允许重定向
if (followUp.body() instanceof UnrepeatableRequestBody) {
streamAllocation.release();
throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
}
if (!sameConnection(response, followUp.url())) {
streamAllocation.release();
streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(followUp.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
} else if (streamAllocation.codec() != null) {
throw new IllegalStateException("Closing the body of " + response
+ " didn't close its backing stream. Bad interceptor?");
}
request = followUp;
priorResponse = response;
}
}
ConnectInterceptor 连接拦截器
/** Opens a connection to the target server and proceeds to the next interceptor. */
//向目标服务器开启一个连接,并传递给下一个拦截器
public final class ConnectInterceptor implements Interceptor {
public final OkHttpClient client;
public ConnectInterceptor(OkHttpClient client) {
this.client = client;
}
@Override public Response intercept(Chain chain) throws IOException {
// 强转为RealInterceptorChain
RealInterceptorChain realChain = (RealInterceptorChain) chain;
// 获取request对象
Request request = realChain.request();
// 通过realChain获取streamAllocation(流分配)
StreamAllocation streamAllocation = realChain.streamAllocation();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
// 获取httpCodec对象 该方法很重要
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
//使用streamAllocation进行链接
RealConnection connection = streamAllocation.connection();
// proceed
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
}
这个拦截器中使用的多个其他类对象,重点代码进行分析
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
查看该方法源码:
public HttpCodec newStream(
OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {
int connectTimeout = chain.connectTimeoutMillis();
int readTimeout = chain.readTimeoutMillis();
int writeTimeout = chain.writeTimeoutMillis();
int pingIntervalMillis = client.pingIntervalMillis();
boolean connectionRetryEnabled = client.retryOnConnectionFailure();
try {
// 寻找健康的链接,其实可以理解为查询有效链接
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);
synchronized (connectionPool) {
codec = resultCodec;
return resultCodec;
}
} catch (IOException e) {
throw new RouteException(e);
}
}
继续查看findHealthyConnection
/**
* Finds a connection and returns it if it is healthy. If it is unhealthy the process is repeated
* until a healthy connection is found.
*/
// 寻找一个链接并返回是否健康,如果不健康就重复处理,直到找到健康的连接为止
private RealConnection findHealthyConnection(int connectTimeout, int readTimeout,
int writeTimeout, int pingIntervalMillis, boolean connectionRetryEnabled,
boolean doExtensiveHealthChecks) throws IOException {
// 死循环
while (true) {
RealConnection candidate = findConnection(connectTimeout, readTimeout, writeTimeout,
pingIntervalMillis, connectionRetryEnabled);
// If this is a brand new connection, we can skip the extensive health checks.
// 如果是一个新的连接,跳过检查,直接返回作为健康的连接
synchronized (connectionPool) {
if (candidate.successCount == 0) {
return candidate;
}
}
// Do a (potentially slow) check to confirm that the pooled connection is still good. If it
// isn't, take it out of the pool and start again.
// 不健康的连接从池子中移除,继续寻找
if (!candidate.isHealthy(doExtensiveHealthChecks)) {
noNewStreams();
continue;
}
return candidate;
}
}
继续查看findConnection
/**
* Returns a connection to host a new stream. This prefers the existing connection if it exists,
* then the pool, finally building a new connection.
*/
// 返回连接到host的新的流,优先选择存在的在池中的连接,最后创建一个新的连接
private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
boolean foundPooledConnection = false;
RealConnection result = null;
Route selectedRoute = null;
Connection releasedConnection;
Socket toClose;
synchronized (connectionPool) {
if (released) throw new IllegalStateException("released");
if (codec != null) throw new IllegalStateException("codec != null");
if (canceled) throw new IOException("Canceled");
// Attempt to use an already-allocated connection. We need to be careful here because our
// already-allocated connection may have been restricted from creating new streams.
// 当前连接作为释放的连接
releasedConnection = this.connection;
// 如果没有新的流释放连接
toClose = releaseIfNoNewStreams();
if (this.connection != null) {
// We had an already-allocated connection and it's good.
// 已经分配了连接,并且是好的,就把当前连接作为结果返回
result = this.connection;
releasedConnection = null;
}
if (!reportedAcquired) {
// If the connection was never reported acquired, don't report it as released!
releasedConnection = null;
}
// result为空,尝试从连接池中获取
if (result == null) {
// Attempt to get a connection from the pool.
Internal.instance.get(connectionPool, address, this, null);
if (connection != null) {
// 找到了连接就对result进行赋值
foundPooledConnection = true;
result = connection;
} else {
selectedRoute = route;
}
}
}
closeQuietly(toClose);
if (releasedConnection != null) {
eventListener.connectionReleased(call, releasedConnection);
}
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
}
if (result != null) {
// result不为空,直接返回
// If we found an already-allocated or pooled connection, we're done.
return result;
}
// If we need a route selection, make one. This is a blocking operation.
// 如果需要一个线路选择,制造一个。这是一个阻塞操作
boolean newRouteSelection = false;
if (selectedRoute == null && (routeSelection == null || !routeSelection.hasNext())) {
newRouteSelection = true;
routeSelection = routeSelector.next();
}
synchronized (connectionPool) {
if (canceled) throw new IOException("Canceled");
if (newRouteSelection) {
// Now that we have a set of IP addresses, make another attempt at getting a connection from
// the pool. This could match due to connection coalescing.
// 现在我们拥有了IP地址集合,尝试从池子中获取一个连接
List<Route> routes = routeSelection.getAll();
for (int i = 0, size = routes.size(); i < size; i++) {
Route route = routes.get(i);
Internal.instance.get(connectionPool, address, this, route);
if (connection != null) {
foundPooledConnection = true;
result = connection;
this.route = route;
break;
}
}
}
//没找到连接,创建一个新的并立即分配
if (!foundPooledConnection) {
if (selectedRoute == null) {
selectedRoute = routeSelection.next();
}
// Create a connection and assign it to this allocation immediately. This makes it possible
// for an asynchronous cancel() to interrupt the handshake we're about to do.
route = selectedRoute;
refusedStreamCount = 0;
result = new RealConnection(connectionPool, selectedRoute);
// 把当前的连接添加到connection.allocations中
acquire(result, false);
}
}
// If we found a pooled connection on the 2nd time around, we're done.
// 如果第二次从池中找到连接,就可以了,直接将result返回
if (foundPooledConnection) {
eventListener.connectionAcquired(call, result);
return result;
}
// Do TCP + TLS handshakes. This is a blocking operation.
// 进行连接
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
connectionRetryEnabled, call, eventListener);
routeDatabase().connected(result.route());
Socket socket = null;
synchronized (connectionPool) {
reportedAcquired = true;
// Pool the connection.
// 将连接放到连接池中
Internal.instance.put(connectionPool, result);
// If another multiplexed connection to the same address was created concurrently, then
// release this connection and acquire that one.
// 如果另外一个多路连接连接到相同的地址,释放当前这个,并且接受新的那个
// 重复连接进行替换
if (result.isMultiplexed()) {
socket = Internal.instance.deduplicate(connectionPool, address, this);
result = connection;
}
}
closeQuietly(socket);
eventListener.connectionAcquired(call, result);
return result;
}
看完了findConnection继续查看noNewStreams();
/** Forbid new streams from being created on the connection that hosts this allocation. */
// 阻止从已分配的host创建新的stream
public void noNewStreams() {
Socket socket;
Connection releasedConnection;
synchronized (connectionPool) {
releasedConnection = connection;
// 释放
socket = deallocate(true, false, false);
if (connection != null) releasedConnection = null;
}
// 安全关闭socket
closeQuietly(socket);
if (releasedConnection != null) {
eventListener.connectionReleased(call, releasedConnection);
}
}
继续查看deallocate
/**
* Releases resources held by this allocation. If sufficient resources are allocated, the
* connection will be detached or closed. Callers must be synchronized on the connection pool.
*
* <p>Returns a closeable that the caller should pass to {@link Util#closeQuietly} upon completion
* of the synchronized block. (We don't do I/O while synchronized on the connection pool.)
*/
private Socket deallocate(boolean noNewStreams, boolean released, boolean streamFinished) {
assert (Thread.holdsLock(connectionPool));
if (streamFinished) {
this.codec = null;
}
if (released) {
this.released = true;
}
Socket socket = null;
if (connection != null) {
if (noNewStreams) {
// 如果没有新的流的时候,不创建新的连接
connection.noNewStreams = true;
}
if (this.codec == null && (this.released || connection.noNewStreams)) {
// 释放连接
release(connection);
if (connection.allocations.isEmpty()) {
connection.idleAtNanos = System.nanoTime();
if (Internal.instance.connectionBecameIdle(connectionPool, connection)) {
socket = connection.socket();
}
}
connection = null;
}
}
return socket;
}
CallServerInterceptor call服务器拦截器
/** This is the last interceptor in the chain. It makes a network call to the server. */
最后一个拦截器,使网络连接到服务器
public final class CallServerInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
// 通过httpStream获取httpCode对象
HttpCodec httpCodec = realChain.httpStream();
StreamAllocation streamAllocation = realChain.streamAllocation();
RealConnection connection = (RealConnection) realChain.connection();
// 通过realChain获取request对象
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
// 请求头开始监听
realChain.eventListener().requestHeadersStart(realChain.call());
httpCodec.writeRequestHeaders(request);
// 请求头结束监听
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
Response.Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
// If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
// Continue" response before transmitting the request body. If we don't get that, return
// what we did get (such as a 4xx response) without ever transmitting the request body.
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
httpCodec.flushRequest();
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(true);
}
if (responseBuilder == null) {
// Write the request body if the "Expect: 100-continue" expectation was met.
realChain.eventListener().requestBodyStart(realChain.call());
long contentLength = request.body().contentLength();
CountingSink requestBodyOut =
new CountingSink(httpCodec.createRequestBody(request, contentLength));
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
realChain.eventListener()
.requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
} else if (!connection.isMultiplexed()) {
// If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
// from being reused. Otherwise we're still obligated to transmit the request body to
// leave the connection in a consistent state.
streamAllocation.noNewStreams();
}
}
// 完成请求
httpCodec.finishRequest();
// 响应Builder为空则httpCodec不再读取响应头
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
// 通过responseBuilder构建response实例
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
// code为100,重新尝试读取实际响应
if (code == 100) {
// server sent a 100-continue even though we did not request one.
// try again to read the actual response
responseBuilder = httpCodec.readResponseHeaders(false);
response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
code = response.code();
}
realChain.eventListener()
.responseHeadersEnd(realChain.call(), response);
if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
// 连接升级,但是我们确保拦截器看到一个非空响应体
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}
最后还有一个HttpCodec
/** Encodes HTTP requests and decodes HTTP responses. */
用于加密HTTP请求和解密HTTP响应
public interface HttpCodec {
ConnectionPool
/**
* Manages reuse of HTTP and HTTP/2 connections for reduced network latency. HTTP requests that
* share the same {@link Address} may share a {@link Connection}. This class implements the policy
* of which connections to keep open for future use.
*/
// 管理http和http2连接的复用来减少网络延迟,具有相同地址的http请求共享连接,实现了连接保持开启策略,用于将来使用
public final class ConnectionPool {
/**
* Create a new connection pool with tuning parameters appropriate for a single-user application.
* The tuning parameters in this pool are subject to change in future OkHttp releases. Currently
* this pool holds up to 5 idle connections which will be evicted after 5 minutes of inactivity.
*/
// 初始拥有5个空闲连接,不活动的连接5分钟后将会被移除
public ConnectionPool() {
this(5, 5, TimeUnit.MINUTES);
}
主要方法
get() 获取
// 返回一个回收连接,如果该连接不存在返回null,如果地址没有被路由分配链路为空
/**
* Returns a recycled connection to {@code address}, or null if no such connection exists. The
* route is null if the address has not yet been routed.
*/
@Nullable RealConnection get(Address address, StreamAllocation streamAllocation, Route route) {
assert (Thread.holdsLock(this));
for (RealConnection connection : connections) {
// 判断连接是否携带流分配到地址
if (connection.isEligible(address, route)) {
// 将当前连接添加到streamAllocation中
streamAllocation.acquire(connection, true);
return connection;
}
}
return null;
}
deduplicate() 对于重复的连接进行替换,类似hashmap键重复,值覆盖
/**
* Replaces the connection held by {@code streamAllocation} with a shared connection if possible.
* This recovers when multiple multiplexed connections are created concurrently.
*/
@Nullable Socket deduplicate(Address address, StreamAllocation streamAllocation) {
assert (Thread.holdsLock(this));
for (RealConnection connection : connections) {
if (connection.isEligible(address, null)
&& connection.isMultiplexed()
&& connection != streamAllocation.connection()) {
return streamAllocation.releaseAndAcquire(connection);
}
}
return null;
}
put() 添加
void put(RealConnection connection) {
assert (Thread.holdsLock(this));
if (!cleanupRunning) {
cleanupRunning = true;
executor.execute(cleanupRunnable);
}
// 向连接池中添加连接
connections.add(connection);
}
evictAll() 清空
/** Close and remove all idle connections in the pool. */
// 从池中关闭并移除所有空闲的连接
public void evictAll() {
List<RealConnection> evictedConnections = new ArrayList<>();
synchronized (this) {
for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) {
RealConnection connection = i.next();
if (connection.allocations.isEmpty()) {
connection.noNewStreams = true;
evictedConnections.add(connection);
i.remove();
}
}
}
for (RealConnection connection : evictedConnections) {
closeQuietly(connection.socket());
}
}
call.cancel(); 取消call,取消请求
查看RealCall的cancel方法
@Override public void cancel() {
retryAndFollowUpInterceptor.cancel();
}
继续跟进RetryAndFollowUpInterceptor的cancel方法
/**
* Immediately closes the socket connection if it's currently held. Use this to interrupt an
* in-flight request from any thread. It's the caller's responsibility to close the request body
* and response body streams; otherwise resources may be leaked.
*
* <p>This method is safe to be called concurrently, but provides limited guarantees. If a
* transport layer connection has been established (such as a HTTP/2 stream) that is terminated.
* Otherwise if a socket connection is being established, that is terminated.
*/
// 立即关闭socket连接,立即关闭任何线程动态的请求,该调用用来关闭响应体和响应体流数据,然而资源可能泄露。
// 回调是安全的,并且提供了有效的担保
// 如果传输层已经进入开启状态,会被终止
public void cancel() {
canceled = true;
StreamAllocation streamAllocation = this.streamAllocation;
if (streamAllocation != null) streamAllocation.cancel();
}