Netty服务端启动原理

服务端启动代码如下

public class EchoServer {
    static final int PORT = 8001;
    public static void main(String[] args) {
        // 1. 声明线程池
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            // 2. 服务端引导器
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            // 3. 设置线程池
            serverBootstrap.group(bossGroup, workerGroup)
                    // 4. 设置ServerSocketChannel的类型
                    .channel(NioServerSocketChannel.class)
                    // 5. 设置参数
                    .option(ChannelOption.SO_BACKLOG, 100)
                    // 6. 设置ServerSocketChannel对应的Handler,只能设置一个
                    .handler(new LoggingHandler(LogLevel.INFO))
                    // 7. 设置SocketChannel对应的Handler
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            // 可以添加多个子Handler
                            p.addLast(new LoggingHandler(LogLevel.INFO));
                            p.addLast(new EchoServerHandler());
                        }
                    });

            // 8. 绑定端口
            ChannelFuture f = serverBootstrap.bind(PORT).sync();
            // 9. 等待服务端监听端口关闭,这里会阻塞主线程
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 10. 优雅地关闭两个线程池
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

服务端启动的入口是下面这行代码

ChannelFuture f = serverBootstrap.bind(PORT).sync();

这里主要有两个方法,一个是bind(),一个是sync(),服务端的启动逻辑在bind()方法里,在这里打个断点启动程序。

doBind

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
    public ChannelFuture bind(int inetPort) {
        return bind(new InetSocketAddress(inetPort));
    }
    public ChannelFuture bind(SocketAddress localAddress) {
        // 做一些校验
        validate();
        return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
    }
}

这里只传了一个端口进来,使用InetSocketAddress类构造了一个地址,默认会生成一个0.0.0.0:8001的地址。

接着往下走,进入到doBind方法,开源框架中一般do开头的都是做正事的。

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
    private ChannelFuture doBind(final SocketAddress localAddress) {
        // key1 初始化并注册一些东西
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            // 注册失败
            return regFuture;
        }
        // initAndRegister 里面使用异步的方式
        if (regFuture.isDone()) {
            // 走到这里, 说明上面已经注册完成
            ChannelPromise promise = channel.newPromise();
            // key2 绑定了什么呢? 
            // 是否会执行到这里 取决于initAndRegister()中异步执行的快慢,所以不一定到这里, 这里可以打一个断点
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        } else {
            // 走到这里, 说明还没有注册完成
            final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
            // 设置回调等待完成, 注册完成后会回调这里
            regFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    if (cause != null) {
                        // 注册失败
                        promise.setFailure(cause);
                    } else {
                        // 注册成功
                        promise.registered();
                        // key2 绑定了什么呢? 
                        // 是否会执行到这里 取决于initAndRegister()中异步执行的快慢,所以不一定到这里, 这里可以打一个断点
                        doBind0(regFuture, channel, localAddress, promise);
                    }
                }
            });
            return promise;
        }
    }
}

doBind方法主要做了两件事:

  • initAndRegister()初始化并注册一些东西
  • doBind0绑定一些东西,这里面其实就是调用Java NIO中java.nio.channels.ServerSocketChannelbind方法

initAndRegister

继续进入initAndRegister()方法

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
    final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            // key1, 通过ChannelFactory创建一个 Channel, 使用反射的形式创建一个Channel
            // 反射的类就是我们第4步中设置的 NioServerSocketChannel.class
            channel = channelFactory.newChannel();
            // key2 初始化 Channel
            init(channel);
        } catch (Throwable t) {
            // 异常处理, 忽略
        }
        // key3 注册 Channel
        // 这里用的是NioEventLoopGroup, 所以是将 Channel 注册到 NioEventLoop 中的 java.nio.channels.Selector
        ChannelFuture regFuture = config().group().register(channel);
        // 处理失败, 关闭Channel
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }
        return regFuture;
    }
}

initAndRegister()方法主要做了三件事:

  • channelFactory.newChannel(), 通过反射生成Channel(这里生成的是NioServerSocketChannel), 而且是无参构造方法。

  • init(channel), 初始化Channel

  • config().group().register(channel), 将Channel注册到某个地方。这里用的是NioEventLoopGroup, 所以是将Channel注册到NioEventLoop中的java.nio.channels.Selector

channelFactory.newChannel()

我们这里使用的是NioServerSocketChannel,直接查看它的无参构造方法。

public class NioServerSocketChannel extends AbstractNioMessageChannel
                             implements io.netty.channel.socket.ServerSocketChannel {
    private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
    // 1. 无参构造方法
    public NioServerSocketChannel() {
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
    }    
    // 1.1 使用Java底层的SelectorProvider创建一个Java原生的 java.nio.channels.ServerSocketChannel
    // windows平台下使用的是Windows下的SelectorProvider, 因为ServerSocketChannel是跟操作系统交互的, 所以是平台相关的, 每个平台下都不一样
    private static ServerSocketChannel newSocket(SelectorProvider provider) {
        try {
            return provider.openServerSocketChannel();
        } catch (IOException e) {
            throw new ChannelException(
                    "Failed to open a server socket.", e);
        }
    }
    // 1.2 有参构造方法,参数是Java原生的ServerSocketChannel
    public NioServerSocketChannel(ServerSocketChannel channel) {
        // 调用父类的构造方法, 注意parent参数为null
        // key, 感兴趣的事件为Accept事件
        super(null, channel, SelectionKey.OP_ACCEPT);
        // 创建ChannelConfig
        config = new NioServerSocketChannelConfig(this, javaChannel().socket());
    }
}
public abstract class AbstractNioMessageChannel extends AbstractNioChannel {
    // 1.2.1
    protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        // 调用父类构造方法
        super(parent, ch, readInterestOp);
    }
}

查看父类方法

public abstract class AbstractNioChannel extends AbstractChannel {
    // 1.2.1.1
    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        // 调用父类的构造方法,parent为null
        super(parent);
        // ch为Java原生的Channel
        this.ch = ch;
        // 监听事件, 这里为Accept事件
        this.readInterestOp = readInterestOp;
        try {
            // 将channel设置为非阻塞
            ch.configureBlocking(false);
        } catch (IOException e) {
            // 忽略异常......
        }
    }
}

继续看父类方法

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
    // 1.2.1.1.1
    protected AbstractChannel(Channel parent) {
        // 此时parent为null
        this.parent = parent;
        // 生成一个id
        id = newId();
        // 这里调用的是 io.netty.channel.nio.AbstractNioMessageChannel.newUnsafe
        // 返回的是 new NioMessageUnsafe()
        unsafe = newUnsafe();
        // 这里返回的是 DefaultChannelPipeline
        pipeline = newChannelPipeline();
    }
    protected ChannelId newId() {
        return DefaultChannelId.newInstance();
    }
    protected DefaultChannelPipeline newChannelPipeline() {
        return new DefaultChannelPipeline(this);
    }
}

看看DefaultChannelPipeline实例化做了什么

public class DefaultChannelPipeline implements ChannelPipeline {
    // 1.2.1.1.1.1
    protected DefaultChannelPipeline(Channel channel) {
        this.channel = ObjectUtil.checkNotNull(channel, "channel");
        succeededFuture = new SucceededChannelFuture(channel, null);
        voidPromise =  new VoidChannelPromise(channel, true);
        // ChannelPipeline中默认有两个节点,head和tail,且是双向链表
        tail = new TailContext(this);
        head = new HeadContext(this);

        head.next = tail;
        tail.prev = head;
    }
}

NioServerSocketChannel创建完成,主要做了如下几件事情

  1. NioServerSocketChannel里面会有一个Java原生的java.nio.channels.ServerSocketChannel

  2. 记录监听事件为Accept事件

  3. Channel分配一个id

  4. Channel创建一个unsafe,io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe

  5. Channel分配一个pipeline(DefaultChannelPipeline),默认情况,这是一个双向链表:HeadContext<=>TailContext

init(channel)

接着看init(channel)方法

public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
    @Override
    void init(Channel channel) {
        
        setChannelOptions(channel, newOptionsArray(), logger);
        setAttributes(channel, newAttributesArray());
        // 从Channel中取出ChannelPipeline, 上面创建的
        ChannelPipeline p = channel.pipeline();
        // 子Channel的配置, 子Channel也就是SocketChannel
        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);
        // 这里往ChannelPipeline中新增了一个 ChannelInitializer
        // 里面有个initChannel方法, 后面有地方会回调这个方法
        // 
        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) {
                final ChannelPipeline pipeline = ch.pipeline();
              	// 这里是第6步设置的LoggingHandler
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }
                // 这里使用异步的方式提交一个任务
                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        // 往ChannelPipeline中新增了一个ChannelHandler
                        // 把子Channel相关的参数传到这个Handler里面
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }
}

此时的ChannelPipeline链条为: HeadContext<=>ChannelInitializer<=>TailContext

config().group().register(channel)

查看源码,可以发现,这里的group()返回的就是我们的bossGroup(NioEventLoopGroup),所以这里就是调用NioEventLoopGroupregister(channel)方法。

// NioEventLoopGroup
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
    @Override
    public ChannelFuture register(Channel channel) {
        return next().register(channel);
    }
    @Override
    public EventLoop next() {
        // 这里会选择一个EventLoop(NioEventLoop)出来
        return (EventLoop) super.next();
    }
}

然后来到了EventLoopregister(channel)方法:

// NioEventLoopGroup
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
    @Override
    public ChannelFuture register(Channel channel) {
        return register(new DefaultChannelPromise(channel, this));
    }
    @Override
    public ChannelFuture register(final ChannelPromise promise) {
        ObjectUtil.checkNotNull(promise, "promise");
        // 这里unsafe()返回的是 NioMessageUnsafe 
        promise.channel().unsafe().register(this, promise);
        return promise;
    }
}

最后,又调回了ChannelUnsaferegister()方法,这里第一个参数是this,也就是NioEventLoop,第二个参数是刚创建的ChannelPromise

// io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
    protected abstract class AbstractUnsafe implements Unsafe {
        @Override
        public final void register(EventLoop eventLoop, final ChannelPromise promise) {
            ObjectUtil.checkNotNull(eventLoop, "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;
            }
            // key1, 将上面传进来的EventLoop跟Channel进行绑定
            AbstractChannel.this.eventLoop = eventLoop;
            // 判断当前线程是否跟EventLoop线程是同一个, 这里肯定不是同一个, 所以会执行后面的else语句
            if (eventLoop.inEventLoop()) {
                // key2,调用register0
                register0(promise);
            } else {
                try {
                    // 提交一个异步任务
                    eventLoop.execute(new Runnable() {
                        @Override
                        public void run() {
                            // key2, 调用register0, 可以在这里打个断点
                            register0(promise);
                        }
                    });
                } catch (Throwable t) {
                    // 省略......
                }
            }
        }
    }
}

上面提交了一个异步任务,这里的EventLoopNioEventLoop

eventLoop.execute(new Runnable() {
    @Override
    public void run() {
        // key2, 调用register0, 可以在这里打个断点
        register0(promise);
    }
});

NioEventLoop类似于Java线程池里面的工作线程,每个NioEventLoop里面有自己的任务队列。这里执行execute,会先把任务放到任务队列中,然后再判断NioEventLoop中的线程是否启动,如果没有,则会新建一个线程并启动,最终会执行NioEventLoop#run方法,这里面有一个死循环,会执行任务队列里面的任务以及监听Socket事件。

可以在这里打个断点看看里面的细节。

接着,跟踪到register0()方法中:

// io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
    protected abstract class AbstractUnsafe implements Unsafe {
        private void register0(ChannelPromise promise) {
            try {
                // 做一些检查, 跳过
                if (!promise.setUncancellable() || !ensureOpen(promise)) {
                    return;
                }
                boolean firstRegistration = neverRegistered;
                // key1, 调用doRegister()方法
                // 这里其实是将EventLoop中的Selector与Java原生的Channel绑定在一起
                doRegister();
                neverRegistered = false;
                registered = true;

                // key2,调用invokeHandlerAddedIfNeeded()
                // 触发添加Handler的回调
                // 前面init(channel)方法, 往ChannelPipeline总添加了一个ChannelInitializer, ChannelInitializer的initChannel方法就是在这一步完成的
                // 这一步之后, 前面init(channel)方法添加的ChannelInitializer执行会执行initChannel方法后就会把自己移除掉
                // 最后ChannelPipeline里面应该是: HeadContext<=>LoggineHandler<=>TailContext
                // 而ServerBootstrapAcceptor还没有加入到ChannelPipeline中,
                // 因为它设置了使用EventLoop的线程执行,当前线程就是EventLoop的线程
                // 所以, 添加ServerBootstrapAcceptor会在当前任务执行完毕才会执行
                pipeline.invokeHandlerAddedIfNeeded();

                safeSetSuccess(promise);
                // 调用ChannelPineline的fireChannelRegistered(), 实际是调用的各个ChannelHandler的channelRegistered()方法
                // 
                pipeline.fireChannelRegistered();
                // Channel是否已经激活, 此时还未绑定到具体的地址,所以还未激活
                if (isActive()) {
                    if (firstRegistration) {
                        pipeline.fireChannelActive();
                    } else if (config().isAutoRead()) {
                        beginRead();
                    }
                }
            } catch (Throwable t) {
                // 省略......
            }
        }
    }
}

register0方法执行完成后,ChannelPipeline里面应该是:HeadContext<=>LoggineHandler<=>TailContext

接着看doRegister()里面做了什么

public abstract class AbstractNioChannel extends AbstractChannel {
    @Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
                // key,将EventLoop中的Selector与Java原生的Channel绑定在一起
                // 第三个参数是this, 这里就是NioServerSocketChannel
                selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
                return;
            } catch (CancelledKeyException e) {
                // 忽略......
            }
        }
    }
}

这里的监听集合设置为了0, 也就是什么都不监听。后续应该有某个地方会需要修改这个selectionKey的监听集合。

发现是在AbstractNioChannel#doBeginRead这个方法里面,重新设置了监听SelectionKey.OP_ACCEPT事件。

通过Debug发现,等NioServerSocketChannel准备就绪后,会调用DefaultChannelPipeline#fireChannelActive,进而触发到AbstractNioChannel#doBeginRead方法。

到这里,initAndRegister()方法内部就分析完成了。

还有个地方需要注意,前面往ChannelPipeline中新增了一个ChannelInitializer, 里面有个initChannel方法,执行了如下操作

p.addLast(new ChannelInitializer<Channel>() {
    @Override
    public void initChannel(final Channel ch) {
        final ChannelPipeline pipeline = ch.pipeline();
      	// 这里是第6步设置的LoggingHandler
        ChannelHandler handler = config.handler();
        if (handler != null) {
            pipeline.addLast(handler);
        }
        // 这里使用异步的方式提交一个任务
        ch.eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                // 往ChannelPipeline中新增了一个ChannelHandler
                // 把子Channel相关的参数传到这个Handler里面
                pipeline.addLast(new ServerBootstrapAcceptor(
                        ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
            }
        });
    }
});

因为这里使用的是异步的方式提交了一个任务,所以需要等前面的任务执行完成后才会执行到上面这个任务。

所以此时ChannelPipeline里面还是:HeadContext<=>LoggineHandler<=>TailContext

doBind0

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
    private static void doBind0(
            final ChannelFuture regFuture, final Channel channel,
            final SocketAddress localAddress, final ChannelPromise promise) {
        // 这里也是提交一个异步任务
        channel.eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                if (regFuture.isSuccess()) {
                    // key, 调用Channel(NioServerSocketChannel)的bind()方法, 因为提交的是异步任务, 所以这里要打一个断点
                    channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    promise.setFailure(regFuture.cause());
                }
            }
        });
    }
}

上面往NioEventLoop里面提交了一个一步任务。

NioEventLoop会从任务队列里面获取任务并执行,会先执行到这个任务,该任务是在前面ChannelInitializer里面的initChannel方法提交的。

ch.eventLoop().execute(new Runnable() {
    @Override
    public void run() {
        // 往ChannelPipeline中新增了一个ChannelHandler
        // 把子Channel相关的参数传到这个Handler里面
        pipeline.addLast(new ServerBootstrapAcceptor(
                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
    }
});

这个任务执行完后,此时ChannelPipeline里面应该是: HeadContext<=>LoggineHandler<=>ServerBootstrapAcceptor<=>TailContext

上面任务执行完,然后才会执行到doBind0提交的任务。

// NioServerSocketChannel
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
    @Override
    public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        // 调用的是pipeline(DefaultChannelPipeline)的bind()方法
        return pipeline.bind(localAddress, promise);
    }
}

进入pipeline(DefaultChannelPipeline)的bind()方法

public class DefaultChannelPipeline implements ChannelPipeline {
    @Override
    public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        // 从尾开始调用,也就是outbound
        return tail.bind(localAddress, promise);
    }
}

此时的ChannelPipelineHeadContext<=>LoggineHandler<=>ServerBootstrapAcceptor<=>TailContext

outbound类型的pineple实际为HeadContext=>LoggingHandler=>TailContext

这里主要贴出重要代码

先执行到LoggingHandler.bind方法,这里主要是打日志

public class LoggingHandler extends ChannelDuplexHandler {
    @Override
    public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
        if (logger.isEnabled(internalLevel)) {
            logger.log(internalLevel, format(ctx, "BIND", localAddress));
        }
        ctx.bind(localAddress, promise);
    }
}

再执行HeadContext.bind方法

public class DefaultChannelPipeline implements ChannelPipeline {
    final class HeadContext extends AbstractChannelHandlerContext
            implements ChannelOutboundHandler, ChannelInboundHandler {
        @Override
        public void bind(
                ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
            // unsafe是io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe
            unsafe.bind(localAddress, promise);
        }    
    }
}

进入NioMessageUnsafe.bind方法

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
    protected abstract class AbstractUnsafe implements Unsafe {
        @Override
        public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
            assertEventLoop();
            // 忽略......
            boolean wasActive = isActive();
            try {
                // key,绑定地址
                // 这里其实是调用NioServerChannel的doBind方法
                doBind(localAddress);
            } catch (Throwable t) {
                safeSetFailure(promise, t);
                closeIfClosed();
                return;
            }

            if (!wasActive && isActive()) {
                // 成功激活,调用pipeline.fireChannelActive()方法
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.fireChannelActive();
                    }
                });
            }

            safeSetSuccess(promise);
        }
    }
}

进入NioServerChanneldoBind方法

public class NioServerSocketChannel extends AbstractNioMessageChannel
                             implements io.netty.channel.socket.ServerSocketChannel {
    @SuppressJava6Requirement(reason = "Usage guarded by java version check")
    @Override
    protected void doBind(SocketAddress localAddress) throws Exception {
        // 根据不同的JDK版本调用不同的方法
        if (PlatformDependent.javaVersion() >= 7) {
            // 我使用的是JDK8
            // 调用java.nio.channels.ServerSocketChannel的bind方法
            javaChannel().bind(localAddress, config.getBacklog());
        } else {
            javaChannel().socket().bind(localAddress, config.getBacklog());
        }
    }    
}

可以看到,doBind0()最后也是通过Java原生java.nio.channels.ServerSocketChannelbind()方法来实现的。

总结

  1. initAndRegister (),初始化。

    • 通过反射创建NioServerSocketChannel,有下面几个变量

      • ch,java.nio.channels.ServerSocketChannel,Java NIO中的类
      • readInterestOp,记录要监听的事件为:SelectionKey.OP_ACCEPT
      • unsafe,io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe
      • pipeline,DefaultChannelPipeline,这是一个双向链表,默认链为:HeadContext<=>TailContext
    • 初始化NioServerSocketChannel

      这里主要是往NioServerSocketChannelpipeline中添加了一个ChannelInitializer

      此时的ChannelPipeline链条为: HeadContext<=>ChannelInitializer<=>TailContext

    • 从线程组中(bossGroup)选了一个NioEventLoop

      • 此时NioServerSocketChannel就绑定了一个NioEventLoop

      • 往这个NioEventLoop提交了一个异步任务[①]io.netty.channel.AbstractChannel.AbstractUnsafe#register0

      异步任务的功能:将NioServerSocketChannel中的java.nio.channels.ServerSocketChannelNioEventLoopSelector绑定。然后执行pipeline.invokeHandlerAddedIfNeeded()方法。这里会触发ChannelInitializer执行initChannel方法,该方法会把第6步设置的handler添加到ChannelPipeline,然后将自己从ChannelPipeline移除。最后还往NioEventLoop添加了一个异步任务[②],异步任务是往ChannelPipeline添加ServerBootstrapAcceptor

  2. doBind0绑定监听端口

    NioEventLoop添加了一个异步任务[③],异步任务的功能:通过Java NIO中的java.nio.channels.ServerSocketChannel绑定本地端口。

需要注意上面提交的三个异步任务是按顺序执行的,因为NioEventLoop里面只有一个线程执行任务队列里面的任务。

第①个任务执行完,此时ChannelPipeline为:HeadContext<=>LoggineHandler<=>TailContext

第②个异步执行完,

此时ChannelPipeline为:HeadContext<=>LoggineHandler<=>ServerBootstrapAcceptor<=>TailContext

首次往NioEventLoop里面提交任务会触发NioEventLoop#run方法执行,这个方法里面是一个死循环,里面负责监听Selector上的IO事件和执行提交进来的异步任务。

重要组件说明

ChannelHandler

ChannelHandler是核心业务处理接口,用于处理或拦截IO事件,并将其转发到ChannelPipeline中的下一个ChannelHandler,运用的是责任链设计模式。

ChannelHandler分为入站和出站两种:ChannelInboundHandlerChannelOutboundHandler,一般不建议直接实现这两个接口,而是它们的抽象类:

  • SimpleChannelInboundHandler:处理入站事件,它可以帮我们做资源的自动释放等操作。不建议直接使用 ChannelInboundHandlerAdapter
  • ChannelOutboundHandlerAdapter:处理出站事件。
  • ChannelDuplexHandler:既可以处理入站也可以处理出站。

ChannelHandlerContext

默认实现DefaultChannelHandlerContext,里面有ChannelHandlerChannelPipeline的引用。

ChannelPipeline中的节点就是一个个ChannelHandlerContext

ChannelPipeline

ChannelPipelineChannelHandler的集合,它负责处理和拦截入站和出站的事件和操作,每个Channel都有一个ChannelPipeline与之对应,会自动创建。

ChannelPipeline中存储的是ChannelHandlerContext链,通过这个链把ChannelHandler连接起来。

  • 一个Channel对应一个ChannelPipeline
  • 一个ChannelPipeline包含一条双向的ChannelHandlerContext
  • 一个ChannelHandlerContext中包含一个ChannelHandler
  • 一个Channel会绑定到一个EventLoop
  • 一个NioEventLoop维护了一个Selector(使用的是 Java 原生的 Selector
  • 一个NioEventLoop相当于一个线程
  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值