游戏SDK架构设计之代码实现——网络框架
OKHttp 源码解析(一)
OKHttp 源码解析(二)拦截器
目前大多数的网络框架都是使用 OKHttp ,Retrofit 也是基于 OKHttp,OKHttp 使用简单,但出现的问题不少,也借此机会了解一下 OKHttp 的源码。
本文的 OKHttp 源码基于 3.4.2 版本。
OKHttp 的官方文档:https://square.github.io/okhttp/
在 OKHttp 的源码入口就提示了如何简单实用 OKHttp:
OkHttpClient client = ...
// 创建 OkHttpClient
OkHttpClient clientWith30sTimeout = client.newBuilder().readTimeout(30, TimeUnit.SECONDS).build();
// 调用 newCall,传入请求体,execute执行任务
Response response = clientWith30sTimeout.newCall(request).execute();
OkHttpClient
类OkHttpClient
采用建造者模式,通过 Builder 去配置初始化变量,没有配置的采用默认值。成员变量如下:
public Builder() {
// 调度器dispatcher = new Dispatcher();// 协议,默认的有 Protocol.HTTP_2, Protocol.SPDY_3, Protocol.HTTP_1_1protocols = DEFAULT_PROTOCOLS;proxySelector = ProxySelector.getDefault();cookieJar = CookieJar.NO_COOKIES;socketFactory = SocketFactory.getDefault();connectionSpecs = DEFAULT_CONNECTION_SPECS;//域名校验verifyAsIpAddress(host)? verifyIpAddress(host, certificate): verifyHostname(host, certificate)
// 会检验 IP 地址和域名,可以通过这个接口检验更多内容hostnameVerifier = OkHostnameVerifier.INSTANCE;certificatePinner = CertificatePinner.DEFAULT;proxyAuthenticator = Authenticator.NONE;
// 身份验证器authenticator = Authenticator.NONE;
//连接池,默认 5 个空闲链接,5分钟内不活动被释放connectionPool = new ConnectionPool();
//DNS设置dns = Dns.SYSTEM;
//是否从HTTP重定向到HTTPSfollowSslRedirects = true;
//是否重定向followRedirects = true;
//连接失败时是否重连,这个重连只有1次retryOnConnectionFailure = true;//连接超时,默认 10sconnectTimeout = 10_000;
//读取超时readTimeout = 10_000;
//写入超时writeTimeout = 10_000;}
Request
类这个类也是实用的建造者设计模式,构建请求体,成员变量比较简单。
// 请求地址private HttpUrl url;
// 请求方式,GET(默认) 、POST、DELETE、PUT、PATCH、HEADprivate String method;
// 请求头,Headers 类来设置请求头内容private Headers.Builder headers;
// 请求体,设置 contentType 和 请求参数private RequestBody body;
// 标志,用来标志某个线程,可用于取消某个线程请求private Object tag;
RealCall
请求调用接口由调用 newCall
返回一个 RealCall
对象
/*** Prepares the {@code request} to be executed at some point in the future.*/@Override public Call newCall(Request request) {return new RealCall(this, request);}
RealCall
实现了 Call
接口,可执行 execute
(同步请求) 、enqueue
(异步请求)、cancel
方法,是应用端和服务端的桥梁,展示应用端的请求和服务端返回的数据responseCallback
。
execute
判断 Call
是否请求过,一个 Call
只能执行一次,如果已经执行过则抛出异常。
调用 executed
方法将 Call
添加到队列里。
client.dispatcher().executed(this);// 将 Call 添加到队列里
synchronized void executed(RealCall call) {runningSyncCalls.add(call);}
// 其中 runningSyncCalls
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */private final Deque runningAsyncCalls = new ArrayDeque<>();
调用 getResponseWithInterceptorChain
构建拦截器链,遍历拦截器,执行请求,执行完成时返回结果。
// 同步请求
try {// 调用 executed 方法将 Call 添加到队列里。client.dispatcher().executed(this);// 调用 getResponseWithInterceptorChain 构建拦截器链Response result = getResponseWithInterceptorChain();if (result == null) throw new IOException("Canceled");return result;} finally {// 将 Call 从队列中移除client.dispatcher().finished(this);}private Response getResponseWithInterceptorChain() throws IOException {// Build a full stack of interceptors.List 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);}
将 Call
从队列中移除 client.dispatcher().finished(this);
AsyncCall
实现,AsyncCall
就是一个 Runnable
对象。执行步骤和同步任务差不多,都会先检查 Call 是否执行过,然后调用 getResponseWithInterceptorChain
构建拦截器链,遍历拦截器,执行请求,执行完成时返回结果。
拦截器的源码解析见下篇文章:
final class AsyncCall extends NamedRunnable {// ...@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);}}}
Dispatcher
类OKHttp 请求的调度器,内部维护了一个线程池和一些队列。
// 并行的最大请求数,有接口可修改
private int maxRequests = 64;
//每台主机同时执行的最大请求数
private int maxRequestsPerHost = 5;
// 线程池
private ExecutorService executorService;
public synchronized ExecutorService executorService() {if (executorService == null) {executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));}return executorService;}// 队列
// 已经准备好的异步请求
private final Deque readyAsyncCalls = new ArrayDeque<>();// 正在运行的异步请求,包括已经取消的和运行未完成的
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */private final Deque runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */private final Deque runningSyncCalls = new ArrayDeque<>();
OkHttpClient
通过 newCall
访问 RealCall
execute
enqueue
Dispatcher
将 Call
添加到队列getResponseWithInterceptorChain
遍历拦截器,执行请求getResponse
Call
从 队列移除。