一、知识介绍:
1. 先说下OSI七层模型
应用层(指的是 http https rtmp)
↓
表示层(如 数据加密解密/编码解码)
↓
会话层(把 传输端口与接收端口建立会话)
↓
传输层(这里就是他通过socket套接字抽象层 tcp长连接 udp非长连接)
↓
网络层(通过IP查找目标主机 , 找到路径, 发送报包)
↓
数据链路层(交换机)
↓
物理层(物理传输 网线,把数据变成比特流 二进制数据传输)
2.在OSI之后转变衍生出TCP/IP四层模型
应用层(OSI中的 应用+表示+会话)
↓
传输层
↓
网络层
↓
主机至网络层(OSI中的 数据链路+物理)
3.OkHttp的改造是针对哪一层?
实际上OkHttp框架并非直接使用应用层的来进行改造的框架,而是基于传输层的Socket对应用层的Http的封装改造.
4.Http协议概念
Http1.0 每发起一次请求, socket 请求->响应 三次握手, 断开则有四次挥手.
Http1.1 发起一次请求后, 客户端跟服务端进行连接, 会通过keeplive对connection连接进行长连接保持, 后续不断继续发起请求, 也只会有之前的一次"三次握手"操作, 直到断开 才会出现一次"四次挥手". 但是缺点是对服务器压力大.
5.Http Request请求分析
上面是Post的情况, 如果是get 就没有"请求体"和"请求体长度"和"请求体类型"
二、主线流程源码分析
OkHttp主要的几个类 OkHttpClient Request Response Call Callback
类介绍
OkHttpClient.java 采用构建者模式进行对象实例 , Builder是内部类, 内部存有预设参数 调度器 连接池等:
public static final class Builder {
// 调度器
Dispatcher dispatcher;
@Nullable Proxy proxy;
List<Protocol> protocols;
List<ConnectionSpec> connectionSpecs;
final List<Interceptor> interceptors = new ArrayList<>();
final List<Interceptor> networkInterceptors = new ArrayList<>();
EventListener.Factory eventListenerFactory;
ProxySelector proxySelector;
CookieJar cookieJar;
@Nullable Cache cache;
@Nullable InternalCache internalCache;
SocketFactory socketFactory;
@Nullable SSLSocketFactory sslSocketFactory;
@Nullable CertificateChainCleaner certificateChainCleaner;
HostnameVerifier hostnameVerifier;
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;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
if (proxySelector == null) {
proxySelector = new NullProxySelector();
}
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;
callTimeout = 0;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
}
Request.java 也是采用构建者模式, 存放如url header之类的信息
public static class Builder {
@Nullable HttpUrl url;
String method;
Headers.Builder headers;
@Nullable RequestBody body;
}
Call.java 其实是接口
public interface Call extends Cloneable {
Request request();
Response execute() throws IOException;
void cancel();
boolean isExecuted();
boolean isCanceled();
Timeout timeout();
Call clone();
interface Factory {
Call newCall(Request request);
}
}
CallBack.java 也是接口
public interface Callback {
// 失败在这里
void onFailure(Call call, IOException e);
// 成功在这里
void onResponse(Call call, Response response) throws IOException;
}
开始分析
在OkHttp, 创建Call实例实际上是通过OkHttpClient.java中的newCall方法来进行的
@Override public Call newCall(Request request) {
// 这里面实际上是用RealCall.java来进行操作的
return RealCall.newRealCall(this, request, false /* for web socket */);
}
final class RealCall implements Call {
// 实例化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.transmitter = new Transmitter(client, call);
return call;
}
// 同步请求
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.timeoutEnter();
transmitter.callStart();
try {
client.dispatcher().executed(this);
return getResponseWithInterceptorChain();
} finally {
client.dispatcher().finished(this);
}
}
// 异步请求
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
}
上述代码中能看到, 返回call对象其实是在RealCall.java进行的, 而实际上这个RealCall 就是Call接口的实现类, 无论是同步请求方法execute 还是异步请求enqueue. 都在这实现类进行的.
现在看看异步请求的处理
在我们实际使用中, 做异步请求只需要走call的这个enqueue方法传入回调接口Callback即可.
现在我们来分析下enqueue做了什么
@Override public void enqueue(Callback responseCallback) {
// 在这里加一把锁,在锁里面判断 如果该call的请求已被执行过, 那么就会抛出异常
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
// 这个可以先不管
transmitter.callStart();
// 这里着重看
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
client.dispatcher() 就是从OkHttpClient中拿取dispatcher调度器. 而在前面也已经分析过dispatcher调度器其实就是在OkHttpClient通过构建者模式Builder()的时候, 已经被初始化了. 默认情况是直接new出来的.
换而言之 而真正执行enqueue方法的 其实是Dispatcher调度器, 而且我们原先的Callback对象还被一个叫AsyncCall的玩意给封装起来了. 注意好了, 这个AsyncCall其实是RealCall里面的一个内部类来着. 而AsyncCall是真正执行异步任务的, 待会再讲
我们可以先看看调度器的enqueue其实做了啥.
public final class Dispatcher {
// 这里是调度器enqueue加入队列的真正实现
void enqueue(AsyncCall call) {
synchronized (this) {
// 把AsyncCall添加到一个叫readyAsyncCalls的"就绪队列"中去
readyAsyncCalls.add(call);
// 这里面是跟webSocket相关的, 这次先不管他
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
// 在这里确认事件并开始执行
promoteAndExecute();
}
/**
* 这里大概的意思是把call任务 从ready就绪状态 改变为 running运行状态.并在一个线程池里面进行运行. 最终返回的东西是"调度器是否正在运行"
* 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.
*
* @return true if the dispatcher is currently running calls.
*/
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List<AsyncCall> executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
// 在这里对"就绪队列"进行遍历
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
// 抽出下一个异步任务
AsyncCall asyncCall = i.next();
// 如果"运行队列"总数已经超过了最大请求值, 那就会终止循环
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
// 如果该异步任务每个Host主机的请求大于最大请求值, 则本次循环终止
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
// 前面都没问题,则表示可以继续往后走,移除掉"就绪队列"当前这位元素
i.remove();
// Host主机请求数自增
asyncCall.callsPerHost().incrementAndGet();
// 当前异步任务添加到"可执行队列"
executableCalls.add(asyncCall);
// 当前异步任务添加到"运行队列"
runningAsyncCalls.add(asyncCall);
}
// 只要"运行队列"长度不为0 那么都记录"正在运行"
isRunning = runningCallsCount() > 0;
}
// 从"可执行队列"里面进行遍历
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
// 先执行executorService(), 拿到线程池
// 在线程池上进行真实请求
asyncCall.executeOn(executorService());
}
return isRunning;
}
// 在这里创建/获取线程池
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;
}
}
到了asyncCall.executeOn(executerService())这里后, 我们得知, 这里做了这么多事情, 其实就是为了弄一条"可执行队列"出来, 真正的运行 依然还得看AsyncCall, 前面留下的伏笔 现在来看看吧
final class RealCall implements Call {
// 别忘了AsyncCall其实是RealCall里面的内部类, 继承的是NamedRunnable 而NameRunnable实现了Runnable.具体可以往下拉 拉到代码块的最后面, 有NamedRunnable的介绍
final class AsyncCall extends NamedRunnable {
// 这就是前面封装在AsyncCall里面的原装CallBack.
private final Callback responseCallback;
// 这个就是Host主机的请求数
private volatile AtomicInteger callsPerHost = new AtomicInteger(0);
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
/**
* 这里就是真正的异步任务处理方法了
* 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);
transmitter.noMoreExchanges(ioException);
// 如果出了任何异常情况 那就会直接走callBack的失败接口回调方法.
responseCallback.onFailure(RealCall.this, ioException);
} finally {
// 如果不顺利的话 那就会走调度器的结束.表示该call任务不再运作了.
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
// 这里真正执行
@Override protected void execute() {
// 这个仅仅是个标记, 标记为一旦发生异常, 是开发者造成的还是框架出问题
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
// 拿到响应消息, 这里是一个重点, 这里是责任链设计模式, 通过拦截器来获取响应信息
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
// 在这里进行成功回调
responseCallback.onResponse(RealCall.this, response);
} catch (IOException e) {
if (signalledCallback) {
// 如果是true的话, 那就会打印这句话, 表明是开发者写的代码有问题
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
// 走了这里 表明标记为false 表示是本框架请求异常了.
// 在这里作失败回调
responseCallback.onFailure(RealCall.this, e);
}
} catch (Throwable t) {
cancel();
if (!signalledCallback) {
// 走到这里 表明标记为false,那就是真的是框架请求异常了.
IOException canceledException = new IOException("canceled due to " + t);
canceledException.addSuppressed(t);
// 请求出了异常,在这里作失败回调
responseCallback.onFailure(RealCall.this, canceledException);
}
throw t;
} finally {
// 最终结束.表示该call任务不再运作了.
client.dispatcher().finished(this);
}
}
}
// 核心重点来了, 责任链设计模式.
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
// 这里创建拦截器集合
List<Interceptor> interceptors = new ArrayList<>();
// 对okHttpClient现有的拦截器进行获取,添加到集合中去
interceptors.addAll(client.interceptors());
interceptors.add(new RetryAndFollowUpInterceptor(client));
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, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
// 拦截链对原始request对象进行读取,由此获得response对象
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
// 返回response响应体
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
}
// 这就是前面说到的NamedRunnable
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
// 一旦runnable被执行 那么就会走到execute方法. 所以前面的AsyncCall里面的execute就被调起来了
@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其实是根据RealInterceptorChain生成的chain链在其proceed方法之后处理得来的.
看到这里, 我们已经捋顺了OkHttp的整个请求方法的源码思路了, 当然这里留下一块还没分析, 就是"拦截器", 将交由下一篇文章再进行分析.