相关参考:
《Android进阶之光》
https://www.jianshu.com/p/37e26f4ea57b
https://juejin.im/entry/597800116fb9a06baf2eeb63
https://juejin.im/post/5af4482951882567286064e6
本文是基于OkHttp 3.10.0 所作分析
Request request = new Request.Builder().url("https://raw.github.com/square/okhttp/master/README.md").method("GET", null).build();
Call call = mOkHttpClient.newCall(request);
Response response = null;
try {
response = call.execute();// 同步
} catch (IOException e) {
e.printStackTrace();
}
if (response != null) {
Log.d(TAG, "testGet() response = " + response);
} else {
Log.d(TAG, "testGet() response == null");
}
上述就是常见的同步请求代码,如果我们不对 OkHttpClient 进行自定义配置的话,是直接使用以下代码的:
OkHttpClient mOkHttpClient = new OkHttpClient();
ok,就从上面入手吧:
OkHttpClient.java:
public OkHttpClient() {
this(new Builder());
}
OkHttpClient(Builder builder) {// 建造者设计模式
this.dispatcher = builder.dispatcher;// 分发器,主要用于异步请求中
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);// 拦截器,OkHttp的精髓
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);// 网络拦截器,OkHttp的精髓
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;// 缓存
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
if (builder.sslSocketFactory != null || !isTLS) {
this.sslSocketFactory = builder.sslSocketFactory;
this.certificateChainCleaner = builder.certificateChainCleaner;
} else {
X509TrustManager trustManager = systemDefaultTrustManager();
this.sslSocketFactory = systemDefaultSslSocketFactory(trustManager);
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
}
this.hostnameVerifier = builder.hostnameVerifier;
this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
certificateChainCleaner);
this.proxyAuthenticator = builder.proxyAuthenticator;
this.authenticator = builder.authenticator;
this.connectionPool = builder.connectionPool;// 连接复用池
this.dns = builder.dns;
this.followSslRedirects = builder.followSslRedirects;
this.followRedirects = builder.followRedirects;
this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
this.connectTimeout = builder.connectTimeout;// 连接超时时间,1
this.readTimeout = builder.readTimeout;// 读取超时时间
this.writeTimeout = builder.writeTimeout;// 写入超时时间
this.pingInterval = builder.pingInterval;
if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}
一般情况下,我们都是自定义OkHttpClient的配置:
OkHttpClient.Builder builder = new OkHttpClient.Builder();
......// 配置超时时间、拦截器等等
mOkHttpClient = builder.build();
// OkHttpClient.Builder中build()的实现如下:
public OkHttpClient build() {
return new OkHttpClient(this);
}
可见,最后也是调用OkHttpClient(Builder builder)
这个构造。
对于五层因特网协议栈中,传输层对于网络连接与网络断开,主要是依靠TCP的3次握手与4次挥手(对于这个不了解的,可见这篇文章)。为了解决TCP握手和挥手的效率问题,HTTP 有一种叫作 keepalive connections 的机制;而 OkHttp 支持 5 个并发 socket 连接,默认keepAlive时间为5分钟。OkHttp复用连接的操作,都是在ConnectionPool.java完成的(上述代码中的注解1
):核心就是Deque<RealConnection>来存储连接,通过 put、get、connectionBecameIdle和evictAll几个操作来对Deque进行操作,另外通过判断连接中的计数对象StreamAllocation来进行自动回收连接(感兴趣的可看《Android进阶之光》5.6.2节内容)。
Call call = mOkHttpClient.newCall(request);
进入到OkHttpClient.java的newCall():
OkHttpClient.java:
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {// 外观设计模式
return RealCall.newRealCall(this, request, false /* for web socket */);
}
很明显,用到了外观设计模式。继续追踪newRealCall():
RealCall.java:
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.eventListener = client.eventListenerFactory().create(call);
return call;
}
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
// 创建一个默认的重试和重定向拦截器
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
RealCall.java:
@Override public Response execute() throws IOException {
synchronized (this) {
// 如果此Call已经被执行过了,抛异常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();// 2
eventListener.callStart(this);// 调用callStart()表示事件开始执行
try {
client.dispatcher().executed(this);// 3
Response result = getResponseWithInterceptorChain();// 4
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);// 调用callFailed()表示事件失败
throw e;
} finally {
client.dispatcher().finished(this);// 5
}
}
OkHttpClient.java:
final Dispatcher dispatcher;
// 注解3 调用此处
public Dispatcher dispatcher() {
return dispatcher;
}
注解2
处就是向retryAndFollowUpInterceptor加入一个用于追踪堆栈信息的callStackTrace:
RealCall.java:
private void captureCallStackTrace() {
Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
}
注解3
最终的请求是dispatcher来完成的,接下来就开始分析Dispatcher:
Dispatcher.java:
/**
* Policy on when async requests are executed.
*
* Each dispatcher uses an {@link ExecutorService} to run calls internally. If you supply your
* own executor, it should be able to run {@linkplain #getMaxRequests the configured maximum} number
* of calls concurrently.
*/
public final class Dispatcher {
// 最大并发请求数
private int maxRequests = 64;
// 每台主机最大请求数
private int maxRequestsPerHost = 5;
// 每次调度程序空闲时调用的回调(当运行的Call返回零时)。
private @Nullable Runnable idleCallback;
// 执行任务的线程池
/** Executes calls. Created lazily. */
private @Nullable ExecutorService executorService;
// 将要运行的异步请求队列
/** Ready async calls in the order they'll be run. */
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<>();
// 传入一个线程池的实现
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(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
......
}
其中client.dispatcher().executed(this)在Dispatcher的实现为:
Dispatcher.java:
/** Used by {@code Call#execute} to signal it is in-flight. */
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
无非就是加入正在运行的异步队列中。
注解4
返回了一个Response对象,并且不为null时,就把这个对象返回给调用者,所以我们可以得知,网络请求的操作一定在这里执行:
RealCall.java:
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
// 创建存放拦截器的list
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 (!forWebSocket) {
// 如果不是针对WebSocket的网络访问,加入用户自定义的网络拦截器
interceptors.addAll(client.networkInterceptors());
}
// 最后加入的是真正向服务器发出请求且得到响应的拦截器
interceptors.add(new CallServerInterceptor(forWebSocket));
// 创建拦截器链,注意此处的index的值为0,下文会提及
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
// 链式调用拦截器,最后的返回结果就是 Response 对象
return chain.proceed(originalRequest);
}
getResponseWithInterceptorChain()最后是调用了RealInterceptorChain的proceed()方法返回Response对象,查看proceed()源码:
RealInterceptorChain.java:
@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下标超过了过滤器的个数,则抛出异常
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
// index+1,得到下一个RealInterceptorChain
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
// 获取此下标对应的Interceptor
Interceptor interceptor = interceptors.get(index);
// 拦截处理,传入下一个RealInterceptorChain
Response response = interceptor.intercept(next);
// 各种异常处理
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}
Interceptor是一个接口,发现它有5个实现类:
我们挑一个最简单的实现类ConnectInterceptor进行分析:
ConnectInterceptor.java:
/** Opens a connection to the target server and proceeds to the next interceptor. */
public final class ConnectInterceptor implements Interceptor {
public final OkHttpClient client;
public ConnectInterceptor(OkHttpClient client) {
this.client = client;
}
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
......// 省略无关代码
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
}
拿到传入的RealInterceptorChain后,进行相应的处理后,继续调用proceed方法,那么接着刚才的逻辑,index+1,获取下一个interceptor,重复操作,所以现在就很清楚了,这里利用递归循环,也就是okHttp最经典的责任链模式。
众所周知,递归循环一定要有结束循环的条件,那我们猜想,在拦截器链中的最后一个拦截器CallServerInterceptor,一定会结束递归:
CallServerInterceptor.java:
/** This is the last interceptor in the chain. It makes a network call to the server. */
public final class CallServerInterceptor implements Interceptor {
private final boolean forWebSocket;
public CallServerInterceptor(boolean forWebSocket) {
this.forWebSocket = forWebSocket;
}
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
HttpCodec httpCodec = realChain.httpStream();
StreamAllocation streamAllocation = realChain.streamAllocation();
RealConnection connection = (RealConnection) realChain.connection();
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
......
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
......
return response;
}
static final class CountingSink extends ForwardingSink {
long successfulCount;
CountingSink(Sink delegate) {
super(delegate);
}
@Override public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
successfulCount += byteCount;
}
}
}
果然在intercept()中,结束了递归。下面来张图,加深对拦截器的理解(图片取自OkHttp源码分析):
回到RealCall.execute(),无论是否出现异常,一定会执行注解5
finall{}中的语句:
Dispatcher.java:
/** Used by {@code Call#execute} to signal completion. */
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
private void finished(Deque calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
// 从Calls队列(即当前运行的同步队列runningSyncCalls)中移除该 call
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
// false,不执行
if (promoteCalls) promoteCalls();
// 记录当前运行Call的总数量(同步+异步)
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
// 当运行的Call返回零,并且idleCallback不为null,执行它的run方法,进行
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();// 这个线程具体是做什么的,我目前还没搞清楚,知道的麻烦提示下??
}
}
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
其实分析下来,OkHttp主要是利用了分层的设计思想,采用责任链设计模式,每个拦截器Interceptor将传入的Request进行修饰,在CallServerInterceptor进行真正的网络请求,得到原始的Response,再反序返回上一级拦截器,直至返回给最终的调用者
Request request = new Request.Builder().url("http://publicobject.com/helloworld.txt").method("GET", null).build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "请求失败", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String str = response.body().string();
Log.i(TAG, "testAsyncGet() --> onResponse()" + str);
// Log.i(TAG, "testAsyncGet() --> onResponse()"+response);//与response.body().string()不一致
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();
}
});
}
});
创建OkHttpClient、根据Request请求对象,创建一个Call对象 这两个步骤是跟同步请求一样的,所以不再分析。
RealCall.java:
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
// 如果此Call已经被执行过了,抛异常
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
// 注解2中已说明,不再赘述
captureCallStackTrace();
// 调用callStart()表示事件开始执行
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));// 6
}
注解6:
Dispatcher.java:
synchronized void enqueue(AsyncCall call) {
// 当前正在运行的异步数小于 64 ,并且正在运行的请求主机数小于5
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
// 把当前的call加入到正在运行的异步队列中
runningAsyncCalls.add(call);
// 该call加入到线程池中执行
executorService().execute(call);
} else {
// 加入到异步等待队列中
readyAsyncCalls.add(call);
}
}
/** Returns the number of running calls that share a host with {@code call}. */
private int runningCallsForHost(AsyncCall call) {
int result = 0;
for (AsyncCall c : runningAsyncCalls) {
if (c.get().forWebSocket) continue;
if (c.host().equals(call.host())) result++;
}
return result;
}
既然放到了线程池中执行,当然要看看AsyncCall是Runnable还是Callable咯:
NamedRunnable.java:
/**
* Runnable implementation which always sets its thread name.
*/
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();
}
RealCall.java:
final class AsyncCall extends NamedRunnable {
......
@Override protected void execute() {
boolean signalledCallback = false;
try {
// 很熟悉吧?注解4中已讲解过,网络请求的操作在这里执行
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {// 如果call执行了cancel(),返回true
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));// 此处就是调用我们自定义的回调CallBack
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);// 此处就是调用我们自定义的回调CallBack
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);// 此处就是调用我们自定义的回调CallBack
}
} finally {
client.dispatcher().finished(this);
}
}
}
Dispatch.java:
/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) {
// 注解5已讲解过,不同的是finished(Deque calls, T call, boolean promoteCalls)中的形参promoteCalls为true
finished(runningAsyncCalls, call, true);
}
AsyncCall其实是一个Runnable,并且在run()中主要是执行execute()。其实大部分的逻辑是跟同步的方式差不多的,执行dispatcher().finished(this)时,由于promoteCalls为true,会调用promoteCalls():
Dispatcher.java:
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
最关键的一点就是将异步等待队列 readyAsyncCalls 中的 call 移动到 runningAsyncCalls 中,并加入到线程池中执行。
(原图来自okhttp源码分析(一)——基本流程(超详细))