学习了OKHttp的使用,现在来学学源码。
1、OkHttp是一个高效优秀的HTTP库
网上有很多相关的介绍文档 。
2、OKHttp的简单使用实例,实际一般都是和Retrofit结合使用,下面是OKHTTP的使用实例,分别就一二三四步进行分析:
(一) final OkHttpClient client = new OkHttpClient();
okHttpClient = new OkHttpClient.Builder()
.addInterceptor()
.addNetworkInterceptor()
.build();
(二) Request request = new Request.Builder()
.url("https://www.baidu.com/")
.get()
.build();
(三) Response response = client.newCall(request).execute(); //同步请求
(四) okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG,"e="+e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG,"response="+ response.body().toString());
}
});
OKHttp的调用流程图:
下面来看看具体的过程:
一、OKHttpClient对象的创建
1 :创建默认设置的client,或者如上的创建:
public final OkHttpClient client = new OkHttpClient();
2: OKHttpClient通过Builder模式创建
okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new HttpLogginInterceptor())
.cache(new Cache(cacheDir,cacheSize))
.build();
OKHttpClient在一个应用程序中最好使用一个单例,因为每个OKHttpClient实例持有自己的线程池和连接池,重用线程池和连接池可以节省内存,如果每个请求都实例化一个client那么必然造成它本身线程池和连接池的资源浪费。当系统检测到她们已经闲置时,线程和连接资源会被自动释放,当然有需要时也可以主动释放。
* 通过Builder方式构建的OKHttpClient实例可以共享连接池、线程池和配置
* 通过client.dispatcher().executorService().shutdown():停止调度器的service,那么之后的请求都会被拒绝
* 通过client.connectionPool().evictAll():清除连接池,但是守护进程可能并不会马上释放
* 如果client有缓存的话,可以通过client.cache().close()来 关闭,但是不能重复调用,否则可能会crash
* OKHttp使用了守护线程来维护HTTP/2的连接,闲置时则会自动的停止
*/
步骤1:new OKHttpClient:分析OKHttpClient的主体
步骤2:Builder() :分析Builder的构建
步骤1:
OKHTTPClient的关键代码:
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
//Protocol是一个定义了几种协议版本http1.0,http1.1,spdy3,http2的枚举,这里返回的是装载了两个枚举常量Protocol.HTTP_2和Protocol_的不可变list
static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(
Protocol.HTTP_2, Protocol.HTTP_1_1);
//ConnectionSpec:证书
static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);
/**
* 静态Internal实例对象:
* OKHttp3 内部一些更新的API,继承自OKHTTP的包也能够使用,这个Internal仅在OKHTTPClient中使用
* 主要通过builder来设置到client中去
*/
static {
Internal.instance = new Internal() {
}
}
}
//Dispatcher:执行异步请求的代理,下面有这个类的具体分析
final Dispatcher dispatcher;
//网络代理,有Direct、HTTP、SOCKS三种
final Proxy proxy;
//连接规范,配置Socket连接层,对于HTTPS,还能配置安全传输层协议TLS版本与密码套件(CipherSuite)
final List<ConnectionSpec> connectionSpecs;
//Interceptor:拦截器,观察、修改已经发出的请求或得到响应。常用来添加、移除或者转换请求或者
//response的header
final List<Interceptor> interceptors;
final List<Interceptor> networkInterceptors;
//EventListener:请求过程监听器
final EventListener.Factory eventListenerFactory;
/**
* CookieJar:管理cookie,根据URL保存或者取出cookie。
* 可以自定义,有两个方法:
* void saveFromResponse(HttpUrl url, List<Cookie> cookies);
* List<Cookie> loadForRequest(HttpUrl url);
*/
final CookieJar cookieJar;
//Cache :缓存HTTP和HTTPS结果到文件系统,用常见的DiskLruCache来对response进行缓存。
final Cache cache;
//SocketFactory : 通过工厂方法创建Socket
final SocketFactory socketFactory;
final SSLSocketFactory sslSocketFactory;
final CertificateChainCleaner certificateChainCleaner;
//主机名验证器,与HTTPS中的SSL相关,当握手时如果URL的主机名不是可识别的主机,就会要求进行主机名验证
/**
*public interface HostnameVerifier {
//通过session验证指定的主机名是否被允许
boolean verify(String hostname, SSLSession session);
}
*/
final HostnameVerifier hostnameVerifier;
//证书锁,约束哪些证书可以被信任,防止某些证书机构的攻击行为,如果所有证书都不被信任将抛出
//SSLPeerUnverifiedException异常。
final CertificatePinner certificatePinner;
//授权
final Authenticator proxyAuthenticator;
final Authenticator authenticator;
final ConnectionPool connectionPool;
//DNS域名转换
final Dns dns;
}
步骤2;Builder()的创建相关代码:
public Builder() {
dispatcher = new Dispatcher(); //实例线程调度器
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault(); //获取系统的DefaultProxySelector
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
connectionPool = new ConnectionPool(); //实例化一个连接池
//设置默认的连接时间,读写时间
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
}
通过.build()生成OKHTTPClient实例,.将Builder设置的参数设置给OKHTTPClient。
Dispatcher:
/**
* Dispatcher:是异步请求时的代理,所有请求都是在这里进行调用以及处理
* 每个Dispatcher使用一个ExecutorService来调用call请求。
* 如果 提供了自定义的executor,需要支持获取最大的请求数,因为Dispatcher需要根据最大值来维护请求队列
*/
public final class Dispatcher {
//默认的最大请求并发数64
private int maxRequests = 64;
//每个主机最大的请求数
private int maxRequestsPerHost = 5;
//当正在运行的请求数目为0时的回调
private Runnable idleCallback;
//线程池
private ExecutorService executorService;
//已ready的异步请求队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在运行的异步请求队列,包括已经cancel但是还没有finish
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
//正在运行的同步请求队列,包括cancel但没有finish的
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
//可传入自定义的线程池
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
//创建一个线程池实例对象
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
//设置最大的可同时发生的请求数目,如果超过这个请求数,那么就等待正在运行的完成之后再调用
public synchronized void setMaxRequests(int maxRequests) {
if (maxRequests < 1) {
throw new IllegalArgumentException("max < 1: " + maxRequests);
}
this.maxRequests = maxRequests;
//将请求放入正在运行队列中
promoteCalls();
}
public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) {
if (maxRequestsPerHost < 1) {
throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost);
}
this.maxRequestsPerHost = maxRequestsPerHost;
promoteCalls();
}
//异步请求添加:如果此时运行队列大小小于最大值并且共享主机数小于最大值,则添加到正在运行队列并且将请求放入线程池执行,否则只是添加到准备队列中
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
//取消所有的请求
public synchronized void cancelAll() {
for (AsyncCall call : readyAsyncCalls) {
call.get().cancel();
}
for (AsyncCall call : runningAsyncCalls) {
call.get().cancel();
}
for (RealCall call : runningSyncCalls) {
call.cancel();
}
}
//异步请求被调用的过程
private void promoteCalls() {
//1、首先判断此刻运行的Call数目是否>=最大的请求数,或者没有正在等待的请求,则不需要再加载新的请求
if (runningAsyncCalls.size() >= maxRequests) return;
if (readyAsyncCalls.isEmpty()) return
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
/**
* 2、遍历即将运行的的Call,将其的host和正在运行的队列的host比较,如果共享主机数小于最大值的话
* 则将该请求添加到正在运行队列,并且从准备队列中移除
* 将该请求放入线程池执行
* 否则就继续等待。
*
*/
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
//添加的call超过了最大的值,则停止增加新的请求。
if (runningAsyncCalls.size() >= maxRequests) return;
}
}
//返回共享主机的请求数目
private int runningCallsForHost(AsyncCall call) {
int result = 0;
for (AsyncCall c : runningAsyncCalls) {
if (c.host().equals(call.host())) result++;
}
return result;
}
//添加同步请求到运行队列中
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
//请求完成之后从运行队列中移除该请求
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
//将该请求call从相应的队列移除
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
//移除之后再从准备队列往运行队列中添加新的请求【异步请求】
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
//如果运行数目为0并且回调不为空,则调用回调的方法通知接收者请求已完成
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
//获取ready状态中的异步请求队列
public synchronized List<Call> queuedCalls() {
List<Call> result = new ArrayList<>();
for (AsyncCall asyncCall : readyAsyncCalls) {
result.add(asyncCall.get());
}
return Collections.unmodifiableList(result);
}
//返回running状态中的异步请求队列
public synchronized List<Call> runningCalls() {
List<Call> result = new ArrayList<>();
result.addAll(runningSyncCalls);
for (AsyncCall asyncCall : runningAsyncCalls) {
result.add(asyncCall.get());
}
return Collections.unmodifiableList(result);
}
//返回ready状态的异步请求数目,同步请求是马上执行的,所以没有ready这一状态
public synchronized int queuedCallsCount() {
return readyAsyncCalls.size();
}
//返回running状态的请求数目
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
}
二、创建一个网络请求对象Request
Request request = new Request.Builder()
.url("https://www.baidu.com/")
.get()
.build();
来看看Request的关键代码,Request同样通过Builder模式进行创建。
//Request是请求的实体,封装了请求的URL地址、请求方法,请求头、请求参数、请求体、请求响应体等等,
public final class Request {
//HttpUrl封装了请求url\post等相关信息
final HttpUrl url;
//OKHttp支持主流的网络请求,get/post/delete/put等方法
final String method;
//定义请求头
final Headers headers;
//请求体
final RequestBody body;
private volatile CacheControl cacheControl;
/**
* 返回该响应的缓存控制指令,不为空,即使该响应没有包含Cache-Control * *头,、CacheControl是从响应header解析出来的缓存控制指令。
*/
public CacheControl cacheControl() {
CacheControl result = cacheControl;
return result != null ? result : (cacheControl = CacheControl.parse(headers));
}
//判断是否是HTTPS
public boolean isHttps() {
return url.isHttps();
}
public static class Builder {
HttpUrl url;
String method;
Headers.Builder headers;
RequestBody body; //put 或 post、patch时定义的请求体
Object tag;
public Builder() {
this.method = "GET"; //默认为GET方法
this.headers = new Headers.Builder();
}
//设置当前请求为下列的某种请求
public Builder get() {
return method("GET", null);
}
public Builder head() {
return method("HEAD", null);
}
public Builder post(RequestBody body) {
return method("POST", body);
}
public Builder delete(RequestBody body) {
return method("DELETE", body);
}
public Builder delete() {
return delete(Util.EMPTY_REQUEST);
}
public Builder put(RequestBody body) {
return method("PUT", body);
}
public Builder patch(RequestBody body) {
return method("PATCH", body);
}
//拓展方法,可定义任意的请求方法,以及请求体
public Builder method(String method, RequestBody body) {
if (method == null) throw new NullPointerException("method == null");
if (method.length() == 0) throw new IllegalArgumentException("method.length() == 0");
if (body != null && !HttpMethod.permitsRequestBody(method)) {
throw new IllegalArgumentException("method " + method + " must not have a request body.");
}
if (body == null && HttpMethod.requiresRequestBody(method)) {
throw new IllegalArgumentException("method " + method + " must have a request body.");
}
this.method = method;
this.body = body;
return this;
}
}
}
三、通过OKHTTPClient来发起请求
先来看看同步请求:
Response response = okHttpClient.newCall(request).execute();
步骤1:看看okHttpClient.newCall(request)做了什么
//1:生成一个RealCall对象
@Override public Call newCall(Request request) {
return new RealCall(this, request, false );
}
//2:RealCall对象的关键代码
//RealCall实现了Call,Call是一个定义请求的方法的接口,Request定义了请求的基本属性、设置,Call定义了请求的操作,同步、异步、取消等各项操作
final class RealCall implements Call {
final OkHttpClient client;
//失败重连拦截器,在下面有介绍
final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
//事件监听器,监听请求的步骤,用工厂模式创建实例对象
final EventListener eventListener;
//请求对象
final Request originalRequest;
// Guarded by this.
private boolean executed;
//创建RealCall的实例对象
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);
}
步骤2:调用realCall.execute()方法执行请求,下面详细看看这个方法做了什么操作
@Override public Response execute() throws IOException {
synchronized (this) {
// 执行标志,不能重复执行
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
//前面有看到,请求是由Dispatcher来调度的,所以RealCall的execute()进入到Dispatcher的executed()方法中
client.dispatcher().executed(this);
//如何获取请求的返回结果的,可以看到最终的网络请求其实就是在这里做的。
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
看看getResponseWithInterceptorChain()具体的实现:
Response getResponseWithInterceptorChain() throws IOException {
//看到这里添加了一系列的拦截器给interceptors,一个个看看这些拦截器都是做什么的
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
//retryAndFollowUpInterceptor:失败重连重定向拦截器
interceptors.add(retryAndFollowUpInterceptor);
//BridgeInterceptor:从应用程序代码到网络代码的桥梁,将用户的request转化成网络请求,然后根据网络响应转化为用户的response。
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//CacheInterceptor:从缓存中发起request,并将响应写入的缓存中
interceptors.add(new CacheInterceptor(client.internalCache()));
//ConnectInterceptor:打开连接到指定服务器的连接,并且传递给下一个拦截器
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
//CallServerInterceptor:这是拦截器链中的最后一个拦截器,它用于对服务器发起网络请求
interceptors.add(new CallServerInterceptor(forWebSocket));
//最后将所有的拦截器传递给RealInterceptorChain对象,执行proceed()操作
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
可以看出这是一种责任链的模式,每一个拦截器负责一项功能,完成之后往下传递。
//看看chain.proceed()做的具体内容,为了更加简明起见,把异常处理去掉
@Override public Response proceed(Request request) throws IOException {
return proceed(request, streamAllocation, httpCodec, connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
//index是传给RealInterceptorChain的拦截器链的索引
if (index >= interceptors.size()) throw new AssertionError();
calls++;
//调用RealInterceptorChain中的下一个拦截器
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
//获取当前索引的拦截器
Interceptor interceptor = interceptors.get(index);
//执行拦截器的intercept的方法,最终得到返回结果response,返回给RealCall。
Response response = interceptor.intercept(next);
return response;
}
以上是OKHttp请求调用的基本流程。OKHttp请求最重要的的是拦截器的作用,下面再继续看看拦截器的具体内容。