OKHttp 源码解析(四):ConnectInterceptor 拦截器

ConnectInterceptor:

ConnectIntercepter 拦截器的代码比较简单,实际上它是调用了其它实现类,连接拦截器通过 输入输出流进行网络连接

通过 streamAllocation.newStream 创建一个httpCodec:

  @Override
    public Response intercept(Chain chain) throws IOException {
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        Request request = realChain.request();
        StreamAllocation streamAllocation = realChain.streamAllocation();

        // We need the network to satisfy this request. Possibly for validating a conditional GET.
        boolean doExtensiveHealthChecks = !request.method().equals("GET");
        HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
        RealConnection connection = streamAllocation.connection();

        return realChain.proceed(request, streamAllocation, httpCodec, connection);
    }

StreamAllocation:这个类协调Connections,Streams(逻辑HTTP请求/响应对是分层的连接。每个连接都有自己的分配限制,它定义了多少连接可以携带的并发流。HTTP / 1.x  连接可以携带1个流一次,HTTP/2通常携带多个),Calls  三个实体之间的关系:

httpCodec:编码HTTP请求和解码HTTP响应。该类包含了 输出流的创建,HTTP引擎的sentRequestMillis字段的更新,将请求刷新到基础套接字,从HTTP传输中解析响应头的字节,响应流的处理

new Stream() 处理流程:

findHealthyConnection -> findConnection----> releaseIfNoNewStreams ---->deallocate ----> release -->connectionBecameIdle->

new Stream 调用了 findHealthyConnection  -> findConnection  查找一个健康的连接:

toClose = releaseIfNoNewStreams();

这里判断持有的RealConnction 对象是否可以创建一个新的传输流,如果不能创建新的流进行释放:

    private Socket releaseIfNoNewStreams() {
        assert (Thread.holdsLock(connectionPool));
        RealConnection allocatedConnection = this.connection;
        if (allocatedConnection != null && allocatedConnection.noNewStreams) {
            return deallocate(false, false, true);
        }
        return null;
    }

在releaseIfNoNewStreams 方法中调用了  deallocate 方法,该方法是对连接进行释放 移除链接池:

    private Socket deallocate(boolean noNewStreams, boolean released, boolean streamFinished) {
        assert (Thread.holdsLock(connectionPool));

        if (streamFinished) {
            this.codec = null;
        }
        if (released) {
            this.released = true;
        }
        Socket socket = null;
        if (connection != null) {
            if (noNewStreams) {
                connection.noNewStreams = true;
            }
            if (this.codec == null && (this.released || connection.noNewStreams)) {
                release(connection); // todo 释放连接
                if (connection.allocations.isEmpty()) {
                    connection.idleAtNanos = System.nanoTime();
                    //链接用完了重新变为闲置
                    if (Internal.instance.connectionBecameIdle(connectionPool, connection)) { 
                        socket = connection.socket();
                    }
                }
                connection = null;
            }
        }
        return socket;
    }

connectionBecameIdle : 连接用完了重新变为闲置

 /**
     * todo 连接用完了,重新变为闲置
     * Notify this pool that {@code connection} has become idle. Returns true if the connection has
     * been removed from the pool and should be closed.
     */
    boolean connectionBecameIdle(RealConnection connection) {
        assert (Thread.holdsLock(this));
        //todo 比如 服务器返回 Connection: close ,那就会把这个连接关掉 (noNewStreams 设置为true)
        if (connection.noNewStreams || maxIdleConnections == 0) {
            connections.remove(connection);
            return true;
        } else {
            //todo 唤醒wait的清理任务 开始工作
            notifyAll(); // Awake the cleanup thread: we may have exceeded the idle connection
            // limit.
            return false;
        }
    }

当连接被重置为闲置状态时 随后关闭该连接 这里有个前提条件就是 connection.noNewStream 为true 是 否则  不进行连接关闭进行返回

如果连接 connection 实例对象为null 时 分为两种情况:

1、查找连接池 是否有可复用的连接对象:

  //todo 根据代理和不同的ip从连接池中找可复用的连接
                List<Route> routes = routeSelection.getAll();
                for (int i = 0, size = routes.size(); i < size; i++) {
                    Route route = routes.get(i);
                    Internal.instance.get(connectionPool, address, this, route);
                    if (connection != null) {
                        foundPooledConnection = true;
                        result = connection;
                        this.route = route;
                        break;
                    }
                }

2、新建一个RealConnection 连接对象  新建完成后放入连接池中以供复用

   //todo 还是没找到,必须新建一个连接了
            if (!foundPooledConnection) {
                if (selectedRoute == null) {
                    selectedRoute = routeSelection.next();
                }

                // Create a connection and assign it to this allocation immediately. This makes
                // it possible
                // for an asynchronous cancel() to interrupt the handshake we're about to do.
                route = selectedRoute;
                refusedStreamCount = 0;
                //创建一个新的连接对象
                result = new RealConnection(connectionPool, selectedRoute); 
                acquire(result, false);
            }


....
    
         synchronized (connectionPool) {
            reportedAcquired = true;

            // Pool the connection.
            //todo 将新创建的连接放到连接池中
            Internal.instance.put(connectionPool, result);

            // If another multiplexed connection to the same address was created concurrently, then
            // release this connection and acquire that one.
            if (result.isMultiplexed()) {  //todo 是否是多路复用
                socket = Internal.instance.deduplicate(connectionPool, address, this);
                result = connection;
            }
        }

最后调用

streamAllocation.connection(); //connection 方法仅仅返回了一个连接对象    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值