okhttp3现在是我们常用的一个网络请求框架,面试的时候也会问一些相关的问题,之前看了一阵源码,现在写出来看源码总结的一些知识点当作自己的收获。主要是看post请求相关流程。
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("username", "sssss")
.add("password", "111111")
.build();
Request request = new Request.Builder()
.url("https://www.wanandroid.com/user/login")
.post(requestBody)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("okhttp", "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d("okhttp", "onResponse: " + response.body().string());
}
});
这是我们建立一个post请求的时候常用的使用方式。首先看OkHttpClient这个类
public OkHttpClient() {
this(new Builder());
}
继续往里面点
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
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;
pingInterval = 0;
}
可以看到,我们在使用okhttpclient的时候,做了一些初始化的工作。这些参数都是做网络请求服务的。
RequestBody requestBody = new FormBody.Builder()
.add("username", "sssss")
.add("password", "111111")
.build();
Request request = new Request.Builder()
.url("https://www.wanandroid.com/user/login")
.post(requestBody)
.build();
public FormBody build() {
return new FormBody(names, values);
}
FormBody(List<String> encodedNames, List<String> encodedValues) {
this.encodedNames = Util.immutableList(encodedNames);
this.encodedValues = Util.immutableList(encodedValues);
}
public Request build() {
if (url == null) throw new IllegalStateException("url == null");
return new Request(this);
}
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tag = builder.tag != null ? builder.tag : this;
}
上面的就是为了构建出请求体和请求request,这些都没什么好说的,都是作为http请求的一个必要参数。
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("okhttp", "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d("okhttp", "onResponse: " + response.body().string());
}
});
真正的重头戏开始了,这才是真正开始发送请求到返回结果,处理结果的过程,其中一些列的流程是比较清晰的,下面我们追踪一下源码流程。首先我们先看一下newCall这个方法干了什么
/**
* 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 */);
}
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;
}
其实就是构建出一个call对象,来执行enqueue()方法。
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));//最终执行的步骤
}
最终我们看见进入了client.dispatcher().enqueue(new AsyncCall(responseCallback));这个client.dispatcher是在Realcall的构造方法当中进行的赋值,将初始化的okhttpclient赋值。dispatcher实在okhttpClient的构造方法当中创建的对象,所以说最终执行的就是Dispatcher的enqueue方法。这个Dispatcher是okhttp中一个比较重要的类,首先我们先看它的成员
/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
这三个成员可以看出来是三个队列,这三个队列也是Dispatcher所掌控的我们日常使用的一个请求队列。
- readyAsyncCalls :是异步请求的准备队列
- runningAsyncCalls 是异步请求的执行队列
- runningSyncCalls 是同步请求的执行队列
当我们知道这三个队列之后,我们看enqueue方法
private int maxRequests = 64;//最大请求数
private int maxRequestsPerHost = 5;//最大请求同一ip的并发数
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
Dispiatcher会根据条件判断,这么逻辑比较简单,就不仔细说了,如果符合条件,就会异步请求执行队列中,然后执行 executorService().execute(call);不符合条件就加入到异步请求准备队列中。
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 interface ExecutorService extends Executor {
...
}
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
我们不难看出最终的execute方法传入的是一个Runable对象,那么我们这个enqueue(AsyncCall call)这个AsyncCall是什么呢?
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
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();
}
其实就是Runable的实现类,那么最终执行的其实就是AsyncCall 当中的execute方法。AsyncCall是RealCall的内部类,所以我们去看AsyncCall的execute方法,
@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 {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);//请求结束
}
}
}
我们先看流程,当请求最终执行execute方法的时候,首先会经历 getResponseWithInterceptorChain()这个方法返回response对象,然后会经过逻辑判断,是执行成功还是失败的回调,最终都会由Dispatcher类执行结束。由此可见,Dispatcher这个类管理了请求队列,发送请求,结束请求,由名字可以看出,它是分发器类,它干的活也是这个,我只管维护请求队列的开始,结束,我不管期间你做了什么,返回什么response。这个类也是okhttp的一个重点。好,下面我们看一下 getResponseWithInterceptorChain()这个方法。
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 (!forWebSocket) {//判断是否是webSocket连接
interceptors.addAll(client.networkInterceptors());//将用户自定义的网络拦截器加入集合中
}
interceptors.add(new CallServerInterceptor(forWebSocket));//将CallServerInterceptor加入集合中
//创建拦截器链
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
//调用了RealInterceptorChain的proceed方法,返回response
return chain.proceed(originalRequest);
}
代码量非常少,但是逻辑比较清晰,然后我们看看Interceptor和 Interceptor.Chain
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
/**
* Returns the connection the request will be executed on. This is only available in the chains
* of network interceptors; for application interceptors this is always null.
*/
@Nullable Connection connection();
Call call();
int connectTimeoutMillis();
Chain withConnectTimeout(int timeout, TimeUnit unit);
int readTimeoutMillis();
Chain withReadTimeout(int timeout, TimeUnit unit);
int writeTimeoutMillis();
Chain withWriteTimeout(int timeout, TimeUnit unit);
}
}
Interceptor.Chain可以看出是一个接口,它其实也是okhttp请求的一个核心,拦截器链,它有自己的实现类RealInterceptorChain
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
this.interceptors = interceptors;
this.connection = connection;
this.streamAllocation = streamAllocation;
this.httpCodec = httpCodec;
this.index = index;
this.request = request;
this.call = call;
this.eventListener = eventListener;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}
这里就是实现类的构造方法,那好,现在我们先缕一缕:
-
首先创建okhttpClient对象,然后创建请求体,创建request,然后通过enqueue方法,发送请求。
-
请求到了Disptcher类中的队列中,然后加入到Disptcher的线程池中,执行execute方法,具体实现,是实现类中的AsycnCall当中的execute方法,然后经过拦截器链式调用,返回response,请求结束。
那么我们就开始研究一下这个链式调用是怎么展开的。
//创建拦截器链
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
我们可以先看创建拦截器链的时候两个比较重要的参数,第一个是我们的拦截器集合,第二个是0,对应的RealInterceptorChain这个类中的index参数,因为Interceptor.chain是接口,所以我们看实现类里的方法。
@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 {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// 重新创建RealInterceptorChain对象,将interceptors传入,同时脚标变成index+1
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
return response;
}
到这再缕一缕:
-
首先创建了连接器链,将连接器集合传给了RealInterceptorChain,然后index传的是0,紧接着调用了RealInterceptorChain的proceed方法。在调用RealInterceptorChain的proceed方法的时候,会新建RealInterceptorChain对象,同时脚标+1,传入的还是之前的集合,这样就能一直的反复调用下去,同时和interceptors集合数量能对应上,直到最后一个集合调用完毕为止,返回response。
其实从代码当中也能看出来
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
}
Interceptor是个接口,系统拦截器都会实现这个方法,最终都会由RealInterceptorChain的Response response = interceptor.intercept(next);这个方法返回response对象。
这样就是链式调用一步一步将request向下执行,然后一步一步向上返回response,最终返回Response对象,也就是 Response response = getResponseWithInterceptorChain();这个方法的详细流程。
小结:
请求的核心是链式调用,通过一个集合去维护,将request一步一步的经过每个连接器向下执行,到最后一个拦截器之后一步一步向上返回response。
这就是okhttp的请求流程。下一章我将会总结一下okhttp的拦截器的作用和连接池原理。