OkHttp 源码详解
OkHttp应该是目前Android平台上使用最为广泛的开源网络库了,Android 在6.0之后也将内部的HttpUrlConnection的默认实现替换成了OkHttp。
这篇文章的目的,了解okhttp的框架原理,以及责任链模式的使用。
1、发送请求
首先看一下,怎么发出一个同步/异步请求。
/**
* 同步发起请求
*
* @throws IOException
*/
private void execute() throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("your url").build();
Response syncResponse = client.newCall(request).execute();
}
/**
* 异步发起请求
*
* @throws IOException
*/
private void enqueue() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("your url").build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
}
});
}
这一段代码就是日常使用OkHttp最常见的用法,跟进源码后,可以得到一张更为详细的流程图,通过这张图来看下内部的逻辑是如何流动的。
其实很简单,只有几个核心类,我们一个个来看一下。
- OkHttpClient
- Request 和 Response
- RealCall
OkHttpClient:这个是整个OkHttp的核心管理类,所有的内部逻辑和对象归OkHttpClient统一来管理,它通过Builder构造器生成,构造参数和类成员很多,这里先不做具体的分析。
Request 和Response:Request是我们发送请求封装类,内部有url, header , method,body等常见的参数,Response是请求的结果,包含code, message, header,body ;这两个类的定义是完全符合Http协议所定义的请求内容和响应内容。
RealCall:负责请求的调度(同步的话走当前线程发送请求,异步的话则使用OkHttp内部的线程池进行);同时负责构造内部逻辑责任链,并执行责任链相关的逻辑,直到获取结果。虽然OkHttpClient是整个OkHttp的核心管理类,但是真正发出请求并且组织逻辑的是RealCall类,它同时肩负了调度和责任链组织的两大重任,接下来我们来着重分析下RealCall类的逻辑。
大致总结就是,OkHttpClient 和 Request 都是使用了 Builder 设计模式,然后,Request 通过 OkHttpClient 把 同步/异步 请求发送出去.
2、同步/异步
我们跟进源码,看一下同步/异步的请求原理
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);
}
}
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
//最大并发请求书
private int maxRequests = 64;
//每个主机的最大请求数
private int maxRequestsPerHost = 5;
private Runnable idleCallback;
/** 执行的线程池. Created lazily. */
private 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;
}
Dispatcher 有两个构造方法,可以自己指定线程池, 如果没有指定, 则会默认创建默认线程池,可以看到核心数为0,缓存数可以是很大, 比较适合执行大量的耗时比较少的任务。
接着看 enqueue是如何实现的
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
当正在运行的异步请求队列中的数量小于64, 并且 正在运行的请求主机数小于5,把请求加载到runningAsyncCalls 中并在线程池中执行, 否则就加入到 readyAsyncCalls 进行缓存等待。
上面可以看到传递进来的是 AsyncCall 然后 execute 那我们看下 AsyncCall方法
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
看到 NamedRunnable 实现了 Runnable,AsyncCall 中的 execute 是对网络请求的具体处理。
Response response = getResponseWithInterceptorChain();
能明显看出这就是对请求的处理,在看它的具体实现之前先看下 client.dispatcher().finished 的方法实现。
/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
/** 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) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
由于 promoteCalls 是true 我们看下 promoteCalls 的方法实现
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.
}
}
根据代码可以明显看出 , 当一个请求结束了调用 finished 方法,最终到promoteCalls就是把 异步等待队列中的请求,取出放到 异步执行队列中。
- 如果异步执行队列已经是满的状态就不加了,return
- 如果 异步等待队列中 没有需要执行的网络请求 也就没有必要进行下一步了 return
- 上面的两条都没遇到,遍历 异步等待队列,取出队首的请求,如果这个请求的 host 符合 (正在执行的网络请求中 同一个host最多只能是5个)的这个条件, 把 等待队列的这个请求移除, 加入到 正在执行的队列中, 线程开始执行。 如果不符合继续 遍历操作。
3、interceptors 拦截器
接着看 RealCall 的 getResponseWithInterceptorChain 方法
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List interceptors = new ArrayList<>();
//用户自己定义的拦截器
interceptors.addAll(client.interceptors());
//系统提供的重试拦截器,失败后的重试和重定向
interceptors.add(retryAndFollowUpInterceptor);
//负责把用户构造的请求转换为发送到服务器的请求 、把服务器返回的响应转换为用户友好的响应 处理 配置请求头等信息
//从应用程序代码到网络代码的桥梁。首先,它根据用户请求构建网络请求。然后它继续呼叫网络。最后,它根据网络响应构建用户响应。
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//处理 缓存配置 根据条件(存在响应缓存并被设置为不变的或者响应在有效期内)返回缓存响应
//设置请求头(If-None-Match、If-Modified-Since等) 服务器可能返回304(未修改)
//可配置用户自己设置的缓存拦截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//连接拦截器 这里才是真正的请求网络
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//配置okhttpClient 时设置的networkInterceptors
//返回观察单个网络请求和响应的不可变拦截器列表。
interceptors.addAll(client.networkInterceptors());
}
//执行流操作(写出请求体、获得响应数据) 负责向服务器发送请求数据、从服务器读取响应数据
//进行http请求报文的封装与请求报文的解析
interceptors.add(new CallServerInterceptor(forWebSocket));
//创建责任链
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
//执行 责任链
return chain.proceed(originalRequest);
}
看下 RealInterceptorChain 的实现
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
Connection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
//创建新的拦截链,链中的拦截器集合index+1
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");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
return response;
}
根据上面的代码 我们可以看出,新建了一个RealInterceptorChain 责任链 并且 index+1,然后 执行interceptors.get(index); 返回Response。
责任链中每个拦截器都会执行chain.proceed()方法之前的代码,等责任链最后一个拦截器执行完毕后会返回最终的响应数据,而chain.proceed() 方法会得到最终的响应数据,这时就会执行每个拦截器的chain.proceed()方法之后的代码,其实就是对响应数据的一些操作。
结合源码,可以得到如下结论:
拦截器按照添加顺序依次执行
拦截器的执行从RealInterceptorChain.proceed()开始,进入到第一个拦截器的执行逻辑
每个拦截器在执行之前,会将剩余尚未执行的拦截器组成新的RealInterceptorChain
拦截器的逻辑被新的责任链调用next.proceed()切分为start、next.proceed、end这三个部分依次执行
next.proceed() 所代表的其实就是剩余所有拦截器的执行逻辑
所有拦截器最终形成一个层层内嵌的嵌套结构
了解了上面拦截器的构造过程,我们再来一个个的分析每个拦截器的功能和作用。
从代码来看,总共添加了五个拦截器(不包含自定义的拦截器如client.interceptors和client.networkInterceptors,这两个后面再解释)。
我们本次分享,只做整体框架的解读,具体每个拦截器的处理不在此做出赘述。
- retryAndFollowUpInterceptor——失败和重定向拦截器
- BridgeInterceptor——封装request和response拦截器
- CacheInterceptor——缓存相关的过滤器,负责读取缓存直接返回、更新缓存
- ConnectInterceptor——连接服务,负责和服务器建立连接 这里才是真正的请求网络
- CallServerInterceptor——执行流操作(写出请求体、获得响应数据) 负责向服务器发送请求数据、从服务器读取响应数据 进行http请求报文的封装与请求报文的解析
4、拦截器demo
个人觉得,okhttp的精髓之一,就是拦截器的理念,针对本理念,写了个简单易懂的demo,请笑纳。
Interceptor拦截器接口
public interface Interceptor {
String intercept(OkHttpChain chain);
}
Interceptor拦截器链
public class OkHttpChain {
private int index = 0;
private List interceptors;
public OkHttpChain(List interceptors, int index) {
this.interceptors = interceptors;
this.index = index;
}
public String process() {
if (index >= interceptors.size()) {
return "";
}
OkHttpChain next = new OkHttpChain(interceptors, index + 1);
Interceptor interceptor = interceptors.get(index);
return interceptor.intercept(next);
}
public void add(Interceptor interceptor) {
interceptors.add(interceptor);
}
}
三个Interceptor拦截器
public class AInterceptor implements Interceptor {
@Override
public String intercept(OkHttpChain chain) {
System.out.println("Interceptor_A");
return "A" + chain.process();
}
}
public class BInterceptor implements Interceptor {
@Override
public String intercept(OkHttpChain chain) {
System.out.println("Interceptor_B");
return "_B" + chain.process();
}
}
public class CInterceptor implements Interceptor {
@Override
public String intercept(OkHttpChain chain) {
System.out.println("Interceptor_C");
return "_C" + chain.process();
}
}
执行
public static void main(String[] args) {
List interceptors = new ArrayList<>();
OkHttpChain chain = new OkHttpChain(interceptors, 0);
interceptors.add(new AInterceptor());
interceptors.add(new BInterceptor());
interceptors.add(new CInterceptor());
String result = chain.process();
System.out.println("result = " + result);
}
执行结果为:
Interceptor_A
Interceptor_B
Interceptor_C
result = A_B_C
参考博客
- OkHttp 源码解析