Okhttp3源码
hi,大家好,我是爱吃香蕉的猴子,Okhttp3的源码之前没有怎深入了解,最近看了很多Okhttp3源码的文章,看的云里雾里,在这我也不贴连接了,整理一篇自己理解的吧。
源码Githup地址 具体的使用过程上面也有介绍,现在步入正题。
从使用步骤切入,再进入源码,最后总结
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder().
url("https://github.com/square/okhttp").
build();
Call call = client.newCall(request);
try {
Response response = call.execute();
call.enqueue(new Callback() {//异步
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
} catch (IOException e) {
e.printStackTrace();
}
上面的代码是规规矩矩的使用范例,现在我们逐一解析
- ①OkHttpClient client = new OkHttpClient.Builder().build();
- 第一步声明client对象,如何声明呢? 为什么通过Builder().builder()?
- 那肯定要看OkHttpClient的代码; path: OkHttp\okhttp\okhttp\src\main\java\okhttp3\OkHttpClient.java
public Builder() {
dispatcher = new Dispatcher();//重点 分析Dispatcher
protocols = DEFAULT_PROTOCOLS;//默认支持的协议
connectionSpecs = DEFAULT_CONNECTION_SPECS;//默认的连接规范
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();//默认的代理选择器,直连
........
- 在这个Builder构造器中,初始化了dispatcher, 在看一下build方法
public OkHttpClient build() {
return new OkHttpClient(this);
}
这样就声明了client对象,并初始化了dispatcher等等.
- ②Request request = new Request.Builder().url().build();
- 这一步就是初始化request; 方法和OkhttpClient很一样, 注释的大概意思:一个HTTP请求。我理解为对请求链接的处理吧
- 然后主要就是要将request(数据请求连接)放入newCall中。
public Builder() {
this.method = "GET"; //get的请求方式
this.headers = new Headers.Builder();
}
- ③Call call = client.newCall(request);
- 上面两步的执行,就是为第三步做准备的,现在 在okhttpclient中newCall方法声明了call对象.
/**
* 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 */);
}
- Call是一个interface, RealCall是真正的实现类,可以着重看RealCall;
- path: OkHttp\okhttp\okhttp\src\main\java\okhttp3\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.transmitter = new Transmitter(client, call);
return call;
}
这样就是初始化了call, 这样就要开始异步请求的工作;
- ④ call.enqueue(new Callback() {
@Override public void enqueue(Callback responseCallback) {
。。。。
//client.dispatcher()返回一个Dispatcher对象,异步请求调度器,里面会对任务进行分辨,是立刻执行还是放入等待队列
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
- 最后的代码中参数new AsyncCall(responseCallback); 我们来猜一下 这个类是干嘛的,我的直觉是和Runnable有关,因为毕竟异步请求嘛
- final class AsyncCall extends NamedRunnable { //果然继承NameRunnable
- 这样RealCall的代码暂时看到这里,现在看Dispatcher的enqueue方法;
path: OkHttp\okhttp\okhttp\src\main\java\okhttp3\Dispatcher.java
- 先看一些变量
private int maxRequests = 64;//最大并发数为64,同时请求
private int maxRequestsPerHost = 5;//每个主机的最大请求数为5
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<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<>();
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);//缓存好的异步调用,都是放在队列里保存
。。。
//TODO
promoteAndExecute();//这一步就是增加线程池
}
进入promoteAndExecute看一下
private boolean promoteAndExecute() {
。。。。。
//如果当前运行的异步请求队列长度小于最大请求数,也就是64,并且主机的请求数小于每个主机的请求数也就是5,
//则把当前请求添加到 运行队列,接着交给线程池ExecutorService处理,否则则放置到readAsyncCall进行缓存,等待执行
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
。。。。。
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//进入线程池
asyncCall.executeOn(executorService());
}
return isRunning;
}
- 网络请求数据,增加线程池 提高效率,进入线程池看一下–> 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;
}
- 小结:添加到线程池后就交给ThreadPoolExecutor去调用,最终则是调用到我们的请求AsyncCall的execute方法。回看上面的代码,异步请求中,我们传递了个Callback接口进来,而在RealCall的enqueue方法中,Callback回调接口被封装到AsyncCall中,而AsyncCall继承与NamedRunnable,而NamaedRunnable则实现了Runnable方法。
-
现在,返回到RealCall中查看executeOn方法;
path: OkHttp\okhttp\okhttp\src\main\java\okhttp3\RealCall.java # 内部类:AsyncCall
/**
* 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);
进入executorService.execute(this);查看
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
//重点: 看OkHttp如何连接返回
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
现在要对返回值处理: getResponseWithInterceptorChain
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
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());
-
这样就分析到了,Okhttp的关键部分拦截器
用户自定义连接器
RetryAndFollowUpInterceptor:在连接失败后进行重新连接,必要时进行重定向,如果调用被取消,可能会抛出IOException
BridgeInterceptor:构建访问网络的桥梁,首先,将用户请求转换成网络请求,然后访问网络,最后将网络响应转换成用户响应。
CacheInterceptor:缓存拦截器,从缓存中获取服务器请求,或者把服务器响应写入缓存中。
ConnectInterceptor:打开一个连接,去连接目标服务器。
CallServerInterceptor:拦截器链中的最后一个链点,通过网络请求服务器。