4、OKHttp有哪些拦截器,分别起什么作用OKHTTP的拦截器是把所有的拦截器放到一个list里,然后每次依次执行拦截器,并且在每个拦截器分成三部分:
- 预处理拦截器内容
- 通过proceed方法把请求交给下一个拦截器
- 下一个拦截器处理完成并返回,后续处理工作 。
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) {interceptors.addAll(client.networkInterceptors());}interceptors.add(new CallServerInterceptor(forWebSocket));Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest);return chain.proceed(originalRequest);}根据源码可知,一共七个拦截器:- addInterceptor(Interceptor),这是由开发者设置的,会按照开发者的要求,在所有的拦截器处理之前进行最早的拦截处理,比如一些公共参数,Header都可以在这里添加 。
- RetryAndFollowUpInterceptor,这里会对连接做一些初始化工作,以及请求失败的充实工作,重定向的后续请求工作 。跟他的名字一样,就是做重试工作还有一些连接跟踪工作 。
- BridgeInterceptor,这里会为用户构建一个能够进行网络访问的请求,同时后续工作将网络请求回来的响应Response转化为用户可用的Response,比如添加文件类型,content-length计算添加,gzip解包 。
- CacheInterceptor,这里主要是处理cache相关处理,会根据OkHttpClient对象的配置以及缓存策略对请求值进行缓存,而且如果本地有了可?的Cache,就可以在没有网络交互的情况下就返回缓存结果 。
- ConnectInterceptor,这里主要就是负责建立连接了,会建立TCP连接或者TLS连接,以及负责编码解码的HttpCodec
- networkInterceptors,这里也是开发者自己设置的,所以本质上和第一个拦截器差不多,但是由于位置不同,所以用处也不同 。这个位置添加的拦截器可以看到请求和响应的数据了,所以可以做一些网络调试 。
- CallServerInterceptor,这里就是进行网络数据的请求和响应了,也就是实际的网络I/O操作,通过socket读写数据 。
频繁的进行建立Sokcet连接和断开Socket是非常消耗网络资源和浪费时间的,所以HTTP中的keepalive连接对于降低延迟和提升速度有非常重要的作用 。
keepalive机制是什么呢?
也就是可以在一次TCP连接中可以持续发送多份数据而不会断开连接 。所以连接的多次使用,也就是复用就变得格外重要了,而复用连接就需要对连接进行管理,于是就有了连接池的概念 。
OkHttp中使用ConectionPool实现连接池,默认支持5个并发KeepAlive,默认链路生命为5分钟 。
怎么实现的?
1)首先,ConectionPool中维护了一个双端队列Deque,也就是两端都可以进出的队列,用来存储连接 。
2)然后在ConnectInterceptor,也就是负责建立连接的拦截器中,首先会找可用连接,也就是从连接池中去获取连接,具体的就是会调用到ConectionPool的get方法 。
RealConnection get(Address address, StreamAllocation streamAllocation, Route route) {assert (Thread.holdsLock(this));for (RealConnection connection : connections) {if (connection.isEligible(address, route)) {streamAllocation.acquire(connection, true);return connection;}}return null;}也就是遍历了双端队列,如果连接有效,就会调用acquire方法计数并返回这个连接 。3)如果没找到可用连接,就会创建新连接,并会把这个建立的连接加入到双端队列中,同时开始运行线程池中的线程,其实就是调用了ConectionPool的put方法 。
public final class ConnectionPool {void put(RealConnection connection) {if (!cleanupRunning) {//没有连接的时候调用cleanupRunning = true;executor.execute(cleanupRunnable);}connections.add(connection);}}4)其实这个线程池中只有一个线程,是用来清理连接的,也就是上述的cleanupRunnableprivate final Runnable cleanupRunnable = new Runnable() {@Overridepublic void run() {while (true) {//执行清理,并返回下次需要清理的时间 。long waitNanos = cleanup(System.nanoTime());if (waitNanos == -1) return;if (waitNanos > 0) {long waitMillis = waitNanos / 1000000L;waitNanos -= (waitMillis * 1000000L);synchronized (ConnectionPool.this) {//在timeout时间内释放锁try {ConnectionPool.this.wait(waitMillis, (int) waitNanos);} catch (InterruptedException ignored) {}}}}}};
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 面试必问的 Redis:RDB、AOF、混合持久化
- 女人单身太久的十大负面表现
- |为什么说人在职场,尊严和面子都是争回来的,不是舔回来的
- 汽车|美国面临40年来最严重通胀 汽油、汽车、食品等统统暴涨:居民直呼疯狂
- 发型|女人50岁以后,放弃黑长直和泡面卷吧,这4种发型更减龄洋气
- 面霜|7款最受英国人喜欢的保湿面霜
- 翡翠|翡翠里面有气泡正常吗?这并不是注胶翡翠,而是另一种替代品
- QQ|成功瘦身!QQ 8.8.88安卓版发布:安装包缩小至625MB
- 吐血整理!这200道阿里P6必备Java面试题,我简直太爱了
- 显示器也走入全面屏时代 它为何更值得选择?
