网络方面
(1)它支持http2.0,在网络请求响应方面使用了多路复用;
(2)内置连接池,减少连接开销,复用连接;
(3)内有Response缓存,缓存响应,避免重复的请求;
(4)对响应体支持gzip压缩,使得传输数据更为轻量;
(5)支持SPDY,允许连接同一主机的所有请求分享一个socket;
拓展方面
(1)支持重定向,重试请求,重写编码拦截器;
(2)支持头部信息拦截,自带CookieJar方法;
(3)支持网络数据传输时的监听;
(4)通过需求能自定义拦截器进行处理;
(1)通过创建OkhttpClientBuidler,实例化OkHttpClient;
(2)当我们发起一个请求时,OKhttpClient内部实现了call.Factory,负责根据请求创建新的Call,接着执行newCall,这里用工厂模式,返回调用了realCall,用dispatcher管理分发了同步异步请求;
(3)execute()以及enqueue()这两个方法最终都用调用realCall中的getResponseWithIntercepterChain()方法,配置着各个拦截器,使用责任链模式获取返回结果;
(4)getResponseWithIntercepterChain方法的拦截器中,依次通过retryAndFollowUpInterceptor->BridgeInterceptor->CacheInterceptor->ConnectInterceptor->CallServerInterceptor五个拦截器对请求依次处理,通过CallServerInterceptor拦截器发送request请求体/头,获得response请求体/头;
(5)最终调用RealInterceptorChain.proceed()启动链式调用;
OkHttpClient client = new OkHttpClient();
查看内部实现的Builder方法
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
proxySelector = ProxySelector.getDefault();
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;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
}
看到该方法里创建了Dispatcher()方法,正如前言的工作流程所说,管理着请求的同步或者异步
OkHttpClient client = new OkHttpClient();
//请求体
RequestBody body = new FormBody.Builder().add("key","value").build()
Request req = new Request.Builder().url("请求地址").post(body).build();
Response response = client.newCall(req).execute();
client.newCall发起了同步请求,得到的响应体response,来看看newCall方法里具体的实现吧
@Override
public Call newCall(Request request) {
return new RealCall(this, request);
}
可以看到这里没有多余步骤,只用了工厂模式,主要是由RealCall来管理实现,进入RealCall的世界,来看看这大世界的精彩。
@Override
public Response execute() throws IOException {
synchronized (this) {
...
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
(1)这里第一步调用了dispatcher().executed(this)方法,执行同步请求;
(2)第二步可以看到之前的流程图,执行完dispatcher方法会执行getResponseWithInterceptorChain方法,这方法很关键,在其中调用了责任链模式的拦截器,返回请求结果;
(3)执行完毕后通知finished方法,我完事了;
dispatcher()涉及的内容不过是选择执行分支,同步/异步。
这里我们选择性看关键代码
private 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 (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
拦截器这一块是OKhttp的核心之一,它不单单只是拦截作用,实际上它把实际的网络请求、缓存、透明压缩等功能都统一了起来,再调用RealInterceptorChain.proceed()方法进行处理,完成一次请求。
这里使用ArrayList保存着各个拦截器;
以上就是各个拦截器的作用,责任链模式还是很精妙。妙极了!(手动滑稽)
@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 httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
这里主要就是创建了一个HTTP2.0的HttpCodec对象,它用okio对socket的读写操作进行封装,更高效的IO操作,期间找到一个可用的,健康的,适合的RealConnection对象,通过它的IO操作创建HttpCoder对象,供后续操作。
@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对象,通过该对象请求/返回数据;
到这同步请求的一整个流程就完毕了。
// RealCall#enqueue
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
// Dispatcher#enqueue
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
一开始调用了RealCall的dispatcher.enqueue方法,接着看dispatcher中的enqueue方法;
当dispatcher在异步执行时,如果当前还能执行一个并发请求,那就立即执行,否则加入 readyAsyncCalls 队列。
new AsyncCall(responseCallback)
它是RealCall 的一个内部类,它实现了 Runnable,所以可以被提交到 ExecutorService 上执行,而它在执行时会调用 getResponseWithInterceptorChain() 函数,并把结果通过 responseCallback 传递给上层使用者,也就是说另开启了线程去执行。
同步请求和异步请求的原理是一样的,都是在 getResponseWithInterceptorChain() 函数中通过 Interceptor 链条来实现的网络请求逻辑,而异步则是把请求加入队列,开启异步线程,通过 ExecutorService 实现。
OKhttp在处理瀑布流照片时,想象一下,如果你有一个瀑布流,然后瀑布流里全部显示的都是图片。现在用户要不断地往下翻看瀑布流的图片。如果这些图片都用同步请求的话,可以想象效率多地下,所以有必要时可以看条件使用异步请求,一个是onFailure,一个是onResponse。这两个方法分别在请求失败和成功的时候调用。注意:这两个方法不是在主线程中。
最后鸣谢CSDN各个文章提供参考