OkHttp - 源码解析
特点:
支持HTTP2/SPDY黑科技(Http2 优化了头部压缩,多路复用多个http请求共用一个TCP连接)
socket自动选择最好路线,并支持自动重连
拥有自动维护的socket连接池,减少握手次数
拥有队列线程池,轻松写并发
拥有Interceptors轻松处理请求与响应(比如透明GZIP压缩,LOGGING)
实现基于Headers的缓存策略
内部有几个比较重要的类:
OkHttpClient:
老规矩还是从最简单的代码来分析一下
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder().
url("https://www.baidu.com").
build();
Call call = client.newCall(request);
try {
//1.同步请求方式
Response response = call.execute();
//2.异步请求方式
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 获取失败
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// 获取成功
}
});
} catch (IOException e) {
e.printStackTrace();
}
先看OkHttpClient
的Build
方法
public Builder() {
dispatcher = new Dispatcher();// 分发器 控制并发 保存了同步和异步的call(线程池执行)
protocols = DEFAULT_PROTOCOLS; // http协议
connectionSpecs = DEFAULT_CONNECTION_SPECS; // 连接配置
eventListenerFactory = EventListener.factory(EventListener.NONE); // 监听器
proxySelector = ProxySelector.getDefault(); // 代理选择
cookieJar = CookieJar.NO_COOKIES;// 默认没有cookie
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;
coBnectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
Build
方法创建了默认的设置,当继续调用build方法时会采用默认设置创建OkHttpClient对象。这时如果需要改变默认的属性,可以这样设置
new OkHttpClient.Builder().connectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS).build();
Request
接着看Request
类
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Object tag;
private volatile CacheControl cacheControl; // Lazily initialized.
}
看到这个类包含类请求的url ,method,headers,body,缓存控制等等。
接着往下分析
Call
@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
this.eventListener = eventListenerFactory.create(this);
}
RealCall是实现Call的子类,真正进行操作的类
Response
首先看下同步请求的
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
try {
// 这边直接放入Running队列中执行
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
真正进行网络请求的是Response result = getResponseWithInterceptorChain();
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
// 负责与服务器建立连接
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);
return chain.proceed(originalRequest);
}
这些Interceptor
完成了一系列的链式使用,CallServerInterceptor
负责向服务器请求数据是最后一个,这个类的intercept
不会再次调用下一个Interceptor
的intercept
方法。ConnectInterceptor
负责建立连接,具体怎么实现可以看下代码,不过肯定逃不过Soket
的使用,再看下CallServerInterceptor
的intercept
方法。
@Override public Response intercept(Chain chain) throws IOException {
HttpCodec httpCodec = ((RealInterceptorChain) chain).httpStream();
StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();
Request request = chain.request();
long sentRequestMillis = System.currentTimeMillis();
httpCodec.writeRequestHeaders(request);
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
}
httpCodec.finishRequest();
Response response = httpCodec.readResponseHeaders()
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
if (!forWebSocket || response.code() != 101) {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
...
return response;
}
最后由HttpCodec
发起网络请求。
然后再看下异步网络请求,按照思路基本流程肯定相似,完成异步操作肯定需要新开线程完成操作。
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
// 先放入Ready队列
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
看下AsyncCall 怎么包装的
// Dispatcher
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
// 提交线程池执行
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
// AsyncCall
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;
}
@Override protected void execute() {
boolean signalledCallback = false;
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) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
// AsyncCall 继承的NamedRunnable
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
Response response = getResponseWithInterceptorChain();
这个就和之前的同步请求一摸一样。
梳理一下整个流程