OkHttp作为时下最受欢迎的网络请求框架之一,它有着自己的优点:
- 使用了众多的设计模式(如:Builder模式、责任链模式等),尤其是在Interceptor中使用的责任链模式,将整个网络请求串联起来最为经典。
- 基于Http请求头、DiskLruCache等缓存策略实现Respose的缓存。
- 内部维护了队列线程池,可以轻松实现并发任务。
- 拥有自动维护的socket连接池,减少握手次数。
除了上面的优点,其实还有很多,这里就不一一详述了。
大家都应该知道OkHttp执行网络请求有两种方式:
- 1、同步网络请求--Call.execute();
- 2.异步网络请求--Call.enqueue(Callback responseCallback)。
那么接下来就从这两个方面进行分析。
1.Call对象的真实面貌——RealCall
-
OkHttpClient#newCall():
@Override public Call newCall(Request request) { return new RealCall(this, request, false /* for web socket */); }
从上述代码,我们发现Call的实现类原来是RealCall,并且创建RealCall对象时,会需要OkHttpClient、Request以及forWebSocket。
RealCall详细分析:
RealCall构造方法
:
构造方法中除了会保存之前的OkHttpClient、Request、boolean forWebSocket之外,还会创建RetryAndFollowUpIntercptor对象,这个对象主要作用是在网络请求是出现异常情况进行重新连接的,具体的分析放在后面。-
execute()
同步请求方法:
既然是同步网络请求,那么就意味着不需要为它去执行分配线程的操作了。并且它应该会直接进入网络请求的操作。@Override public Response execute() throws IOException { ... // 通过Dispatcher管理网络请求——对于同步请求只是将其添加到runningSyncCalls队列中。 client.dispatcher().executed(this); // 构建一堆的网络请求拦截器 Response result = getResponseWithInterceptorChain(); return result; ... }
-
getResponseWithInterceptorChain()
分析:Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. // 1.创建interceptors集合。 List<Interceptor> interceptors = new ArrayList<>(); // 2.添加用户设置的所有的interceptors。 interceptors.addAll(client.interceptors()); // 3.添加错误重连的Interceptor,此对象在构造方法中被创建。 interceptors.add(retryAndFollowUpInterceptor); // 4.添加BridgeInterceptor拦截器,将用户设置的Request进行高度封装(请求头、关于响应体的解gzip)。 interceptors.add(new BridgeInterceptor(client.cookieJar())); // 5.添加处理网络请求对应缓存的拦截器 interceptors.add(new CacheInterceptor(client.internalCache())); // 6.添加进行Socket连接的拦截器 interceptors.add(new ConnectInterceptor(client)); // 7.添加用户定义的网络拦截器 if (!forWebSocket) { interceptors.addAll(client.networkInterceptors()); } // 8.添加Socket下与服务器进行数据读写操作的拦截器。 interceptors.add(new CallServerInterceptor(forWebSocket)); // 9.责任链模式中保存了下一拦截器的链条对象(递归执行的关键)。 Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest); return chain.proceed(originalRequest); }
构建一堆的Interceptor之后,执行RealInterceptorChain中的proceed()方法,开启整个网络请求责任链工作。
RealInterceptorChain # proceed()源码分析:
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException { ... // Call the next interceptor in the chain. // 1.创建保存了下一个interceptor的链条对象。 RealInterceptorChain next = new RealInterceptorChain( interceptors, streamAllocation, httpCodec, connection, index + 1, request); // 2.执行当前当前interceptor的intercept()方法。 Interceptor interceptor = interceptors.get(index); Response response = interceptor.intercept(next); ... return response; }
-
再来分析
enqueue()
异步网络请求:既然是异步网络请求,那么肯定需要两个条件:
1、网络请求的任务体;
2、执行具体任务的工作线程。
@Override public void enqueue(Callback responseCallback) { ... client.dispatcher().enqueue(new AsyncCall(responseCallback)); ... }
-
AsyncCall.execute()源码分析:
protected void execute() { ... // 我们发现其实AsyncCall最后也是做了这件事情 Response response = getResponseWithInterceptorChain(); ... }
2.管理网络请求任务的策略器——Dispatcher
Dispatcher主要的工作就是给异步网络请求任务(AsyncCall)分配工作线程并执行。
-
Dispatcher.enqueue()源码分析:
synchronized void enqueue(AsyncCall call) { // 1.检测正在执行的异步网络请求数是否小于maxRequests // &&相同主机的异步网络请求数是否小于maxRequestsPerHost if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { // 2.满足条件,添加到runningAsyncCalls队列并且执行。 runningAsyncCalls.add(call); executorService().execute(call); } else { // 3.不满足条件,添加到readyAsyncCalls。 readyAsyncCalls.add(call); } }
-
Dispatcher.executed()源码分析:
synchronized void executed(RealCall call) { // 直接添加到runningSyncCalls队列 runningSyncCalls.add(call); }
关于Okhttp的整体工作流程,基本上就是这个样子。至于Interceptor的源码分析,会在后续的文章中给出。最后把整体流程图贴出来: