Android第三方库源码解析:OKHttp

List connectionSpecs;// 传输层版本和连接协议

final List interceptors = new ArrayList<>();// 拦截器

final List networkInterceptors = new ArrayList<>();

EventListener.Factory eventListenerFactory;

ProxySelector proxySelector;

CookieJar cookieJar;

@Nullable Cache cache;

@Nullable InternalCache internalCache;// 内部缓存

SocketFactory socketFactory;

@Nullable SSLSocketFactory sslSocketFactory;// 安全套接层socket 工厂,用于HTTPS

@Nullable CertificateChainCleaner certificateChainCleaner;// 验证确认响应证书 适用 HTTPS 请求连接的主机名。

HostnameVerifier hostnameVerifier;// 验证确认响应证书 适用 HTTPS 请求连接的主机名。

CertificatePinner certificatePinner;// 证书锁定,使用CertificatePinner来约束哪些认证机构被信任。

Authenticator proxyAuthenticator;// 代理身份验证

Authenticator authenticator;// 身份验证

ConnectionPool connectionPool;// 连接池

Dns dns;

boolean followSslRedirects; // 安全套接层重定向

boolean followRedirects;// 本地重定向

boolean retryOnConnectionFailure;// 重试连接失败

int callTimeout;

int connectTimeout;

int readTimeout;

int writeTimeout;

int pingInterval;

// 这里是默认配置的构建参数

public Builder() {

dispatcher = new Dispatcher();

protocols = DEFAULT_PROTOCOLS;

connectionSpecs = DEFAULT_CONNECTION_SPECS;

}

// 这里传入自己配置的构建参数

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);

}

复制代码

2.同步请求流程

Response response = client.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为真正的请求执行者

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;

}

@Override public Response execute() throws IOException {

synchronized (this) {

// 每个Call只能执行一次

if (executed) throw new IllegalStateException(“Already Executed”);

executed = true;

}

captureCallStackTrace();

timeout.enter();

eventListener.callStart(this);

try {

// 通知dispatcher已经进入执行状态

client.dispatcher().executed(this);

// 通过一系列的拦截器请求处理和响应处理得到最终的返回结果

Response result = getResponseWithInterceptorChain();

if (result == null) throw new IOException(“Canceled”);

return result;

} catch (IOException e) {

e = timeoutExit(e);

eventListener.callFailed(this, e);

throw e;

} finally {

// 通知 dispatcher 自己已经执行完毕

client.dispatcher().finished(this);

}

}

Response getResponseWithInterceptorChain() throws IOException {

// Build a full stack of interceptors.

List interceptors = new ArrayList<>();

// 在配置 OkHttpClient 时设置的 interceptors;

interceptors.addAll(client.interceptors());

// 负责失败重试以及重定向

interceptors.add(retryAndFollowUpInterceptor);

// 请求时,对必要的Header进行一些添加,接收响应时,移除必要的Header

interceptors.add(new BridgeInterceptor(client.cookieJar()));

// 负责读取缓存直接返回、更新缓存

interceptors.add(new CacheInterceptor(client.internalCache()));

// 负责和服务器建立连接

interceptors.add(new ConnectInterceptor(client));

if (!forWebSocket) {

// 配置 OkHttpClient 时设置的 networkInterceptors

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());

// 使用责任链模式开启链式调用

return chain.proceed(originalRequest);

}

// StreamAllocation 对象,它相当于一个管理类,维护了服务器连接、并发流

// 和请求之间的关系,该类还会初始化一个 Socket 连接对象,获取输入/输出流对象。

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,

RealConnection connection) throws IOException {

// Call the next interceptor in the chain.

// 实例化下一个拦截器对应的RealIterceptorChain对象

RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,

connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,

writeTimeout);

// 得到当前的拦截器

Interceptor interceptor = interceptors.get(index);

// 调用当前拦截器的intercept()方法,并将下一个拦截器的RealIterceptorChain对象传递下去,最后得到响应

Response response = interceptor.intercept(next);

return response;

}

复制代码

3.异步请求的流程

Request request = new Request.Builder()

.url(“http://publicobject.com/helloworld.txt”)

.build();

client.newCall(request).enqueue(new Callback() {

@Override

public void onFailure(Call call, IOException e) {

e.printStackTrace();

}

@Override

public void onResponse(Call call, Response response) throws IOException {

}

void enqueue(AsyncCall call) {

synchronized (this) {

readyAsyncCalls.add(call);

}

promoteAndExecute();

}

// 正在准备中的异步请求队列

private final Deque readyAsyncCalls = new ArrayDeque<>();

// 运行中的异步请求

private final Deque runningAsyncCalls = new ArrayDeque<>();

// 同步请求

private final Deque runningSyncCalls = new ArrayDeque<>();

// Promotes eligible calls from {@link #readyAsyncCalls} to {@link #runningAsyncCalls} and runs

// them on the executor service. Must not be called with synchronization because executing calls

// can call into user code.

private boolean promoteAndExecute() {

assert (!Thread.holdsLock(this));

List executableCalls = new ArrayList<>();

boolean isRunning;

synchronized (this) {

for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {

AsyncCall asyncCall = i.next();

// 如果其中的runningAsynCalls不满,且call占用的host小于最大数量,则将call加入到runningAsyncCalls中执行,

// 同时利用线程池执行call;否者将call加入到readyAsyncCalls中。

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;

}

复制代码

最后,我们在看看AsynCall的代码。

final class AsyncCall extends NamedRunnable {

private final Callback responseCallback;

AsyncCall(Callback responseCallback) {

super(“OkHttp %s”, redactedUrl());

this.responseCallback = responseCallback;

}

String host() {

return originalRequest.url().host();

}

Request request() {

return originalRequest;

}

RealCall get() {

return RealCall.this;

}

/**

  • Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up

  • if the executor has been shut down by reporting the call as failed.

*/

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!

}

}

}

@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);

}

}

}

复制代码

从上面的源码可以知道,拦截链的处理OKHttp帮我们默认做了五步拦截处理,其中RetryAndFollowUpInterceptor、BridgeInterceptor、CallServerInterceptor内部的源码很简洁易懂,此处不再多说,下面将对OKHttp最为核心的两部分:缓存处理和连接处理(连接池)进行讲解。

二、网络请求缓存处理之CacheInterceptor

@Override public Response intercept(Chain chain) throws IOException {

// 根据request得到cache中缓存的response

Response cacheCandidate = cache != null

? cache.get(chain.request())
null;

long now = System.currentTimeMillis();

// request判断缓存的策略,是否要使用了网络,缓存或两者都使用

CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();

Request networkRequest = strategy.networkRequest;

Response cacheResponse = strategy.cacheResponse;

if (cache != null) {

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 {

// 调用下一个拦截器,决定从网络上来得到response

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.

// 如果本地已经存在cacheResponse,那么让它和网络得到的networkResponse做比较,决定是否来更新缓存的cacheResponse

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.

// 缓存未经缓存过的response

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;

}

复制代码

缓存拦截器会根据请求的信息和缓存的响应的信息来判断是否存在缓存可用,如果有可以使用的缓存,那么就返回该缓存给用户,否则就继续使用责任链模式来从服务器中获取响应。当获取到响应的时候,又会把响应缓存到磁盘上面。

三、ConnectInterceptor之连接池

@Override public Response intercept(Chain chain) throws IOException {

RealInterceptorChain realChain = (RealInterceptorChain) chain;

Request request = realChain.request();

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是对 HTTP 协议操作的抽象,有两个实现:Http1Codec和Http2Codec,顾名思义,它们分别对应 HTTP/1.1 和 HTTP/2 版本的实现。在这个方法的内部实现连接池的复用处理

HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);

RealConnection connection = streamAllocation.connection();

return realChain.proceed(request, streamAllocation, httpCodec, connection);

}

// Returns a connection to host a new stream. This // prefers the existing connection if it exists,

// then the pool, finally building a new connection.

// 调用 streamAllocation 的 newStream() 方法的时候,最终会经过一系列

// 的判断到达 StreamAllocation 中的 findConnection() 方法

private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,

int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {

// 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;

// 释放当前连接的资源,如果该连接已经被限制创建新的流,就返回一个Socket以关闭连接

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!

// 如果该连接从未被标记为获得,不要标记为发布状态,reportedAcquired 通过 acquire() 方法修改

releasedConnection = null;

}

if (result == null) {

// Attempt to get a connection from the pool.

// 尝试供连接池中获取一个连接

Internal.instance.get(connectionPool, address, this, null);

if (connection != null) {

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) {

// 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 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;

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
es = 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;

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-2k0rWlPT-1715485361733)]

[外链图片转存中…(img-DfE292Vm-1715485361735)]

[外链图片转存中…(img-jxLfFWoF-1715485361736)]

[外链图片转存中…(img-nJUpB0Dt-1715485361737)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 30
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值