Netty启动流程

示例工程地址: https://github.com/tshch1989/demo-netty
NioEventLoopGroup:事件处理组,负责管理child线程
NioEventLoop:单线程事件处理器,可NioEventLoopGroup管理,
默认通过ThreadPerTaskExecutor初始化线程,延迟初始化
NioEventLoop是真实的工作线程,它的run方法诠释了netty事件工作流程,
内部默认采用LinkedBlockingQueue为存储队列

初始化流程:
ServerBootstrap.bind()是一切的开始
ServerBootstrap.initAndRegister()
1.创建NioServerSocketChannel,此处是通过配置.channel(NioServerSocketChannel.class)提供
2.初始化NioServerSocketChannel,ServerBootstrap.init()方法
2.1配置NioServerSocketChannel的可选项配置
2.2配置NioServerSocketChannel属性
2.3及其重要,添加NioServerSocketChannel的ChannelInitializer

pipeline.addLast(new ChannelInitializer<Channel>() {
    @Override
    public void initChannel(final Channel ch) {//当NioServerSocketChannel执行register事件后会触发执行handleradd事件,在ChannelInitializer的handleradd中会执行initChannel
        final ChannelPipeline pipeline = ch.pipeline();
        ChannelHandler handler = config.handler();
        if (handler != null) {
            pipeline.addLast(handler);
        }

        ch.eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                pipeline.addLast(new ServerBootstrapAcceptor(//这是一个ChannelInboundHandlerAdapter子类
                        ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
            }
        });
    }
});

2.4NioServerSocketChannel注册到选择器上
2.4.1AbstractUnsafe.register()会创建一个task来执行真实的注册
eventLoop.execute(new Runnable() {//此处的eventLoop是 b.group(bossGroup, workerGroup)的bossGroup组,这也是整个netty启动执行的首个任务,此时会触发NioEventLoop创建实际工作线程

    @Override
    public void run() {
        register0(promise);
    }
});
private void register0(ChannelPromise promise) {
    try {
        // check if the channel is still open as it could be closed in the mean time when the register
        // call was outside of the eventLoop
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
            return;
        }
        boolean firstRegistration = neverRegistered;
        doRegister();//这里实际进行注册selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);,可以看到注册时候没有任何感兴趣事件
        neverRegistered = false;
        registered = true;

        // Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
        // user may already fire events through the pipeline in the ChannelFutureListener.
        pipeline.invokeHandlerAddedIfNeeded();//此处触发NioServerSocketChannel绑定的pipeline中的handler的handlerAdded方法

        safeSetSuccess(promise);
        pipeline.fireChannelRegistered();//此处触发NioServerSocketChannel已经注册的事件
        // Only fire a channelActive if the channel has never been registered. This prevents firing
        // multiple channel actives if the channel is deregistered and re-registered.
        if (isActive()) {//NioServerSocketChannel不会执行此处代码,但是NioSocketChannel会执行此处代码
            if (firstRegistration) {
                pipeline.fireChannelActive();//触发激活事件
            } else if (config().isAutoRead()) {
                // This channel was registered before and autoRead() is set. This means we need to begin read
                // again so that we process inbound data.
                //
                // See https://github.com/netty/netty/issues/4805
                beginRead();//绑定感兴趣的读事件到选择器上
            }
        }
    } catch (Throwable t) {
        // Close the channel directly to avoid FD leak.
        closeForcibly();
        closeFuture.setClosed();
        safeSetFailure(promise, t);
    }
}

ServerBootstrap.doBind0()执行端口绑定
1.AbstractChannel.bind()//javaChannel().bind(localAddress, config.getBacklog());最终调用绑定地址

if (!wasActive && isActive()) {
    invokeLater(new Runnable() {
        @Override
        public void run() {
            pipeline.fireChannelActive();//绑定后触发NioServerSocketChannel的active流程
        }
    });
}

2.AbstractNioChannel.doBeginRead()//准备从channel中读取

protected void doBeginRead() throws Exception {
    // Channel.read() or ChannelHandlerContext.read() was called
    final SelectionKey selectionKey = this.selectionKey;
    if (!selectionKey.isValid()) {
        return;
    }

    readPending = true;

    final int interestOps = selectionKey.interestOps();
    if ((interestOps & readInterestOp) == 0) {//这一步,实际注册感兴趣事件到选择器上,NioServerSocketChannel是accept,按实现不同注册事件不同
        selectionKey.interestOps(interestOps | readInterestOp);
    }
}

到这里NioServerSocketChannel已经绑定到指定地址上,并且绑定了accept事件到选择器上,等待请求连接了
现在让我们打开浏览器,访问localhost:8080,
进入外部连接接入流程:
NioEventLoop.run()一切从这里开始,
1.1strategy = select(curDeadlineNanos);//此处等待选择器返回
1.2NioEventLoop.processSelectedKeysOptimized()处理选择的key
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
unsafe.read();//我们当前是OP_ACCEPT事件,触发读,unsafe可以当做是NioServerSocketChannel
}
1.3AbstractNioMessageChannel.read()方法被调用
1.3.1创建接入的NioSocketChannel
1.3.2触发NioServerSocketChannel上的pipeline的read事件,当前仅有一个handler:ServerBootstrapAcceptor(参照前文:2.3)
在ServerBootstrapAcceptor执行的事情和初始NioServerSocketChannel类似,添加配置选项,添加属性,添加用户定义handler,
在这里配置的:

.childHandler(new ChannelInitializer<SocketChannel>() { // (4)
    @Override
    public void initChannel(SocketChannel ch) throws Exception {
        ch.pipeline().addLast(new DiscardServerHandler());
        ch.pipeline().addLast(new DiscardServerHandler());
    }
})

最后,进行注册:

childGroup.register(child).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (!future.isSuccess()) {
                            forceClose(child, future.cause());
                        }
                    }
                });

注册后,会在active后,把感兴趣事件绑定到选择器上,然后监听到读事件,触发channel的读取事件,然后各个handler执行一遍.
AbstractNioByteChannel.read()//字节流默认读取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值