一直都知道Retrofit-OkHttp-Okio是Square公司封装的用于网络请求的大杀器,项目中也往往都在用Retrofit,看过我之前的文章的朋友应该看到过我的Retrofit源码解析系列, 但是一直没空往下继续深入,去解析OkHttp和Okio,毕竟Retrofit2.0本身就是搭建于OkHttp之上的。
老规矩,先讲一下这个库如何用,最后渐渐的一步步走到这个库的处理过程。
如何使用OkHttp
官方文档很详细的解释了如何使用OkHttp,我们只要一步步跟着就可以了。至于OkHttp优点,或者说为什么使用OkHttp我在这里就略过不提,相信你在看源码的过程中会有自己的理解。
大家在平常的http请求中,最常见的就是使用GET和POST请求,所以,官方Demo也就主要描述了如何处理这两种请求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| final OkHttpClient client = new OkHttpClient(); String get(String url) throws IOException { Request request = new Request.Builder() .url(url) .build(); Response response = client.newCall(request).execute(); return response.body().string(); } public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder() .url(url) .post(body) .build(); Response response = client.newCall(request).execute(); return response.body().string(); }
|
这里可以看出,想要完成一次请求需要以下几个过程:
1. 构造OkHttpClient
对象
2. 创建Request
3. 调用OkHttpClient
对象的newCall()
方法构造Call
对象
4. 调用Call
对象的execute()
方法获取Response
OkHttp 整体调用流程

这次先看图,有了图,跟代码的时候才不会在代码中迷失。
OkHttp源码解读
OkHttpClient
对象
参考流程图,我们先需要一个OkHttpClient
对象,这个对象需要许多参数,所以用建造者模式构建,当然,每个参数都提供了默认值,也可以直接用OkHttpClient
的构造函数来使用默认的实现。
这是各个参数的默认值,需要修改的通过Builder直接修改即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public Builder() { dispatcher = new Dispatcher(); protocols = DEFAULT_PROTOCOLS; connectionSpecs = DEFAULT_CONNECTION_SPECS; 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; }
|
Call
对象
接下来就需要发请求了,发请求需要一个Call
对象, 我们通过newCall()
方法获取这个对象。
1 2 3
| @Override public Call newCall(Request request) { return new RealCall(this, request, false ); }
|
可以看出,真正调用的Call
实现类是RealCall
这个类,默认情况下,这个RealCall
对象的forWebSocket
属性为false。
执行请求
构造完Call
对象,通过Call
对象的execute()
方法同步的执行请求或者enqueue()
方法异步的执行请求。
这里看一下图,会感觉图中的线在这里很密集,而且Dispatcher
对象的线会指给这么多的方法,等我们进入源码中,就可以仔细了解了。
RealCall execute()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Override public Response execute() throws IOException { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); try { client.dispatcher().executed(this); Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } finally { client.dispatcher().finished(this); } }
|
RealCall enqueue()
1 2 3 4 5 6 7 8
| @Override public void enqueue(Callback responseCallback) { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); client.dispatcher().enqueue(new AsyncCall(responseCallback)); }
|
可以看到,这里面的方法都会调用Dispatcher
对象的方法,所以,图中从Dispatcher
对象中发出3条线,代表对应方法执行过程中调用Dispatcher
对象的方法。
虽然Dispatcher
对象在同步和异步的请求中都有它身影的出现,
但是,它主要作用是在异步请求中,开线程池执行异步请求,并用队列保持准备执行的请求。
Dispatcher enqueue()
1 2 3 4 5 6 7 8
| synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); } }
|
在同步请求中,它的作用是保存当前正在执行的请求,那么为什么要进行这样一个操作呢?
Dispatcher executed()
1 2 3
| synchronized void executed(RealCall call) { runningSyncCalls.add(call); }
|
查看Dispatcher
对象的方法,发现有个cancelAll()
方法,原来给用户提供了取消所有请求的操作,那么当前执行的同步请求依旧是要被cancel的,所以,自然要把当前正在执行的同步请求加入其中了。
Dispatcher cancelAll()
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public synchronized void cancelAll() { for (AsyncCall call : readyAsyncCalls) { call.get().cancel(); } for (AsyncCall call : runningAsyncCalls) { call.get().cancel(); } for (RealCall call : runningSyncCalls) { call.cancel(); } }
|
最后获取到Response
对象的时候,通知Dispatcher
请求结束了,Dispatcher
就会在队列里移除相应的请求,所以图中Dispatcher
对象还有一条线指向Response
对象。
重新回到RealCall
对象,发现无论同步还是异步请求,获取Response
的方式都是通过
1
| Response response = getResponseWithInterceptorChain();
|
这样获取的。
我们通过这个方法就获取了Response
对象,说明这个方法为我们做了真正发请求的工作,那么我们先看一张图,看这么复杂的工作,这个方法是如何实现的。

从图中可以看到,这个执行过程像链条一样一环套一环,如果熟悉设计模式,这不就是很好的责任链模式嘛。好了,我们看一下它这里具体做了什么。
RealCall getResponseWithInterceptorChain()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Response getResponseWithInterceptorChain() throws IOException { 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) { interceptors.addAll(client.networkInterceptors()); } interceptors.add(new CallServerInterceptor(forWebSocket)); Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest); return chain.proceed(originalRequest); }
|
可以看到,这其中有下面几种拦截器进行操作。
- 在配置 OkHttpClient 时设置的 interceptors;
- 负责失败重试以及重定向的 RetryAndFollowUpInterceptor;
- 负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应的 BridgeInterceptor;
4.负责读取缓存直接返回、更新缓存的 CacheInterceptor;
- 负责和服务器建立连接的 ConnectInterceptor;
- 配置 OkHttpClient 时设置的 networkInterceptors;
- 负责向服务器发送请求数据、从服务器读取响应数据的 CallServerInterceptor。
可以看到,这个方法最终执行的是RealInterceptorChain
对象的process()
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, Connection connection) throws IOException { if (index >= interceptors.size()) throw new AssertionError(); calls++; if (this.httpCodec != null && !sameConnection(request.url())) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must retain the same host and port"); } if (this.httpCodec != null && calls > 1) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1) + " must call proceed() exactly once"); } RealInterceptorChain next = new RealInterceptorChain( interceptors, streamAllocation, httpCodec, connection, index + 1, request); Interceptor interceptor = interceptors.get(index); Response response = interceptor.intercept(next); if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) { throw new IllegalStateException("network interceptor " + interceptor + " must call proceed() exactly once"); } if (response == null) { throw new NullPointerException("interceptor " + interceptor + " returned null"); } return response; }
|
如果不关心异常状况,核心代码就是如下几行:
1 2 3 4 5
| RealInterceptorChain next = new RealInterceptorChain( interceptors, streamAllocation, httpCodec, connection, index + 1, request); Interceptor interceptor = interceptors.get(index); Response response = interceptor.intercept(next);
|
在process()
的过程中,做了如下几个操作:
1. 生成新的RealInterceptorChain
对象
2. 按index
获取当前interceptors列表中Interceptor
对象
3. 调用Interceptor
对象的intercept()
方法,并将新的RealInterceptorChain
传给Interceptor
对象。
这样,只要Interceptor
对象在intercept()
方法执行过程中调用Chain
对象的proceed()
方法,就会调用传给Interceptor
对象的下一个RealInterceptorChain
对象的proceed()
方法。这样,就像上面说的,一条链一样的不停调用。
好了,上半部分的分析暂时就到这里了,下半部分对各个Interceptor
进行分析。
参考: 拆轮子系列:拆 OkHttp