1

初始化

网络编程 - 初识Netty中,我们看到了客户端Bootstrap调用channel(NioSocketChannel.class)来传递所要初始化的Channel对象。
AbstractBootstrap类,可以看到传递的是ReflectiveChannelFactory,一个Channel的工厂类,赋值给Bootstrap的channelFactory。

public B channel(Class<? extends C> channelClass) {
    if (channelClass == null) {
        throw new NullPointerException("channelClass");
    }
    return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
}

ReflectiveChannelFactory实现了ChannelFactory接口和newChannel方法,这个newChannel方法,会通过传过来的clazz创建一个Channel。这个方法的调用,在Bootstrap的connect()方法中,后面会调用initAndRegister()方法,Bootstrap先暂且略过,我们看看Channel是怎么初始化的,初始化又做了哪些事情。

public T newChannel() {
    try {
        // 这边调用NioSocketChannel的构造方法
        return clazz.getConstructor().newInstance();
    } catch (Throwable t) {
        throw new ChannelException("Unable to create Channel from class " + clazz, t);
    }
}

NioSocketChannel

public NioSocketChannel() {
    // DEFAULT_SELECTOR_PROVIDER是SelectorProvider.provider()
    this(DEFAULT_SELECTOR_PROVIDER);
}

public NioSocketChannel(SelectorProvider provider) {
    // 通过SelectorProvider获取NIO的SocketChannel
    this(newSocket(provider));
}

private static SocketChannel newSocket(SelectorProvider provider) {
    try {
        return provider.openSocketChannel();
    } catch (IOException e) {
        throw new ChannelException("Failed to open a socket.", e);
    }
}

public NioSocketChannel(SocketChannel socket) {
    this(null, socket);
}

public NioSocketChannel(Channel parent, SocketChannel socket) {
    super(parent, socket);
    // NioSocketChannel的属性设置
    config = new NioSocketChannelConfig(this, socket.socket());
}

AbstractNioByteChannel

protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {
    // 关注OP_READ事件
    super(parent, ch, SelectionKey.OP_READ);
}

AbstractNioChannel

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    super(parent);
    this.ch = ch;
    this.readInterestOp = readInterestOp;
    try {
        // 设置非阻塞
        ch.configureBlocking(false);
    } catch (IOException e) {
        // 异常处理,关闭channel并抛异常,代码略
    }
}

AbstractChannel

protected AbstractChannel(Channel parent) {
    this.parent = parent;
    id = newId();
    // 创建一个NioSocketChannel.NioSocketChannelUnsafe的内部类对象
    unsafe = newUnsafe();
    // 创建一个Pipeline,并把当前的Channel赋值给Pipeline
    pipeline = newChannelPipeline();
}

至此,Channel已经创建好了,在其中,他也创建了一个unsafe对象、Pipeline对象以及NioSocketChannelConfig对象。
unsafe类图如下,可以看出,Channel中与socket交互的,其实就是这个unsafe类。
image.png
ChannelPipeline这个类,后面再详细的讲。

注册

Channel初始化完成后,开始注册到EventLoop
在AbstractBootstrap的initAndRegister方法中,初始化Channel后,开始执行ChannelFuture regFuture = config().group().register(channel)
MultithreadEventLoopGroup,这个next,就是通过chooserFactory.newChooser得到的chooser,根据不同的策略来获取EventLoop。也就是说,这个register,其实就是注册到EventLoop中。

public ChannelFuture register(Channel channel) {
    return next().register(channel);
}

SingleThreadEventLoop,先是创建DefaultChannelPromise,这边传递两个参数,一个是channel,一个是this,这个this,就是当前的EventLoop,所以Promise保持了他们两个的关系。再调用register方法时,调用unsafe的register方法。

public ChannelFuture register(Channel channel) {
    return register(new DefaultChannelPromise(channel, this));
}

public ChannelFuture register(final ChannelPromise promise) {
    ObjectUtil.checkNotNull(promise, "promise");
    promise.channel().unsafe().register(this, promise);
    return promise;
}

AbstractChannel.AbstractUnsafe,判断当前调用线程是否是支撑 EventLoop 的线程,如果是直接调用register0,否则,加入到队列。这样的好处,就是减少了线程的上下文切换导致的性能消耗。eventLoop的execute方法参见之前的文章

public final void register(EventLoop eventLoop, final ChannelPromise promise) {
        if (eventLoop == null) {
            throw new NullPointerException("eventLoop");
        }
        if (isRegistered()) {
            promise.setFailure(new IllegalStateException("registered to an event loop already"));
            return;
        }
        if (!isCompatible(eventLoop)) {
            promise.setFailure(
                    new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
            return;
        }
        // 赋值eventLoop,register0方法会用到
        AbstractChannel.this.eventLoop = eventLoop;
        // 如果当前调用线程正是支撑 EventLoop 的线程,那么直接调用register0,否则,加入到队列
        if (eventLoop.inEventLoop()) {
            register0(promise);
        } else {
            try {
                eventLoop.execute(new Runnable() {
                    @Override
                    public void run() {
                        register0(promise);
                    }
                });
            } catch (Throwable t) {
                logger.warn(
                        "Force-closing a channel whose registration task was not accepted by an event loop: {}",
                        AbstractChannel.this, t);
                closeForcibly();
                closeFuture.setClosed();
                safeSetFailure(promise, t);
            }
        }
    }

最终的注册方法。javaChannel()返回的是初始化的provider.openSocketChannel(),eventLoop()返回的是上面register方法赋值的eventLoop,通过SelectableChannel的register方法,把Channel的SocketChannel注册到eventLoop的Selector中。

private void register0(ChannelPromise promise) {
        // 部分代码略
        doRegister();
        // 部分代码略
}

protected void doRegister() throws Exception {
    boolean selected = false;
    for (;;) {
        try {
            selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
            return;
        } catch (CancelledKeyException e) {
            // 部分代码略
        }
    }
}

Channel的生命周期

  • ChannelUnregistered:表示Channel刚刚创建,还没注册到eventLoop,registered的值为false。
  • ChannelRegistered:表示Channel注册到eventLoop。执行完doRegister()方法,把registered的值设为false
  • ChannelActive:表示Channel 处于活动状态(已经连接到它的远程节点)。它现在可以接收和发送数据了,参考下面isActive()方法。
  • ChannelInactive:表示Channel 没有连接到远程节点。
public boolean isActive() {  
    SocketChannel ch = javaChannel();  
    return ch.isOpen() && ch.isConnected();  
}

大军
847 声望183 粉丝

学而不思则罔,思而不学则殆