ServerBootstrap的启动流程

一、ServerBootstrap的启动示例代码 

      EventLoopGroup bossEventLoopGroup = new NioEventLoopGroup(new NamedThreadFactory("bossThread",false));
        EventLoopGroup workEventLoopGroup = new NioEventLoopGroup(new NamedThreadFactory("workThread",false));
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossEventLoopGroup,workEventLoopGroup)
                .channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG,128)
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler( new PojoServerIntitlizer());
        try {
            log.debug(" will start server");
            ChannelFuture closeFuture =  bootstrap.bind(port).sync();
            log.debug("  server is closing");
            closeFuture.channel().closeFuture().sync();
            log.debug("  server is closed");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            bossEventLoopGroup.shutdownGracefully();
            workEventLoopGroup.shutdownGracefully();
            log.debug("  release event loop group");
        }

二、初始化流程

1.ServerBootstrap和bootStrap继承于AbstractBootStrap,都使用模板方式。AbstractBootStrap类有几个比较重要的成员变量。

group:ServerSocketChannel的EventLoopGroup,即reactor-accept的BOSS事件循环线程池组。

channelFactory:创建channel的工厂类,如创建ServerSocketChannel,SocketChannel,

handler:reactor-accept的事件处理类。

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {


    volatile EventLoopGroup group;
    @SuppressWarnings("deprecation")
    private volatile ChannelFactory<? extends C> channelFactory;
    private volatile SocketAddress localAddress;
    private volatile ChannelHandler handler;

public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {

    private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
    private volatile EventLoopGroup childGroup;
    private volatile ChannelHandler childHandler;

  2.设置参数流程。

bootstrap.group(bossEventLoopGroup,workEventLoopGroup) bossEventLoopGroup设置AbstractBootStrap的group,workEventLoopGroup设置为ServerBootstrap的childGroup,

    public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        super.group(parentGroup);
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        this.childGroup = ObjectUtil.checkNotNull(childGroup, "childGroup");
        return this;
    }
channel(NioServerSocketChannel.class) 生成一个根据指定SocketChannel类的反射CHANNEL工厂类,就是根据传入的类反射生成对象。这是设置AbstractBootStrap的类的channelFactory
    public B channel(Class<? extends C> channelClass) {
        return channelFactory(new ReflectiveChannelFactory<C>(
                ObjectUtil.checkNotNull(channelClass, "channelClass")
        ));
    }
.handler(new LoggingHandler(LogLevel.INFO)) 这是设置AbstractBootStrap的类的handler
    public B handler(ChannelHandler handler) {
        this.handler = ObjectUtil.checkNotNull(handler, "handler");
        return self();
    }
.childHandler( new PojoServerIntitlizer());这是设置ServerBootstrap子类的childHandler
    public ServerBootstrap childHandler(ChannelHandler childHandler) {
        this.childHandler = ObjectUtil.checkNotNull(childHandler, "childHandler");
        return this;
    }

三、绑定流程

1.ChannelFuture closeFuture = bootstrap.bind(port).sync();这为起点,会调用AbstractBootStrap的doBind方法

private ChannelFuture doBind(final SocketAddress localAddress) {
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();

            ChannelPromise promise = channel.newPromise();
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
    
    }

2.这里面首先调用initAndRegister,会先创建ServerSocketChannel,并且将channel注册到NioEventLoop的selector中,也就是前文的channel.register(selector,0,eventLoop)

  final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            channel = channelFactory.newChannel();
            init(channel);
        } catch (Throwable t) {
        }

        ChannelFuture regFuture = config().group().register(channel);
        return regFuture;
    }

3.newChannel就是通过前面生成的ReflectChannelFactory调用反射生成一个NioServerSocketChannel对象,这里看一下类的继承图,

 AbstractChannel 有两个成员变量unsafe和pipline,unsafe为操作底层网络IO的接口。pipline也就是我们的管道事件流。也就是说每个channel会自带一个pipline

    protected AbstractChannel(Channel parent) {
        this.parent = parent;
        id = newId();
        unsafe = newUnsafe();
        pipeline = newChannelPipeline();
    }

    protected DefaultChannelPipeline newChannelPipeline() {
        return new DefaultChannelPipeline(this);
    }

 3.创建完channel后,我们来看下初始化流程,这个会调用到子类(ServerBootStrap)的init方法,

这个会做两个事件,

   (1).设置channel的连接选项和属性。

   (2).添加新的handler

这里会为ServerSocketChannel的管道中新增一个handler,用来处理accept-reactor的IO流读取事件,也就是新连接事件。ServerBootstrapAcceptor这个类就是来处理新连接,并注册accept的socketChannel并注册到childGroup的work事件循环以及内部eventLoop的selector中,并且设置子socketChannel的handler为childHandler.这个我们留在接收新连接的流程中讲解。

    void init(Channel channel) {
   setChannelOptions(channel, this.newOptionsArray(), logger);
        setAttributes(channel, (Entry[])this.attrs0().entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));
        ChannelPipeline p = channel.pipeline();
        final EventLoopGroup currentChildGroup = this.childGroup;
        final ChannelHandler currentChildHandler = this.childHandler;
        p.addLast(new ChannelHandler[]{new ChannelInitializer<Channel>() {
            public void initChannel(final Channel ch) {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = ServerBootstrap.this.config.handler();
                if (handler != null) {
                    pipeline.addLast(new ChannelHandler[]{handler});
                }

                ch.eventLoop().execute(new Runnable() {
                    public void run() {
                        pipeline.addLast(new ChannelHandler[]{new ServerBootstrap.ServerBootstrapAcceptor(ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)});
                    }
                });
            }
        }});
    }

4.现在回到第2步,初始化完成了,现在开始将serverSocketChannel注册到bossEventLoop的selector中。ChannelFuture regFuture = config().group().register(channel);这个会调用MultithreadEventLoopGroup.register,也就是从事件循环组的子eventLoop中取下一个NioEventLoop进行注册分配。也就是work-reactor的channel注册机制。

    @Override
    public EventLoop next() {
        return (EventLoop) super.next();
    }

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

 5.我们的NioEventLoop为SingleThreadEventLoop,这个会将channel,当前的eventLoop对象封装成一个promise,进行注册。

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

6.接着找到 ServerSocketChannel的内部的unsafe对象进行注册。这个unsafe就是NioMessageUnsafe

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


public abstract class AbstractNioMessageChannel extends AbstractNioChannel {

    @Override
    protected AbstractNioUnsafe newUnsafe() {
        return new NioMessageUnsafe();
    }
}

7.由于NioMessageUnsafe继承于AbstractUnsafe,所以调用此类的register,这个方法就是首先调用Channel.register,然后触发管道的handlerAdd,channelRegister,channelActive方法。

   public final void register(EventLoop eventLoop, final ChannelPromise promise) {
            ObjectUtil.checkNotNull(eventLoop, "eventLoop");
                AbstractChannel.this.eventLoop = eventLoop;
                if (eventLoop.inEventLoop()) {
                    this.register0(promise);
                } 
        }

     private void register0(ChannelPromise promise) {
            try {

                boolean firstRegistration = this.neverRegistered;
                AbstractChannel.this.doRegister();
                this.neverRegistered = false;
                AbstractChannel.this.registered = true;
                AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded();
                this.safeSetSuccess(promise);
                AbstractChannel.this.pipeline.fireChannelRegistered();
                if (AbstractChannel.this.isActive()) {
                    if (firstRegistration) {
                        AbstractChannel.this.pipeline.fireChannelActive();
                    } else if (AbstractChannel.this.config().isAutoRead()) {
                        this.beginRead();
                    }
                }
            }
        }

8.AbstractChannel.this.doRegister();这个就是把ServerSocketChannel注册到NioEventLoop的selector中去。这时还没有监听事件。

  AbstractNioChannel
  protected void doRegister() throws Exception {
        boolean selected = false;
        while(true) {
            try {
                this.selectionKey = this.javaChannel().register(this.eventLoop().unwrappedSelector(), 0, this);
                return;
            } 
        }
    }

生成的selectKey如下: 

9.invokeHandlerAddedIfNeeded会调用到父类CHANNEL管道的channelHandler,也就是在我们初始化时第三步加入的handler

 在这里才会真正触发handler的initChannel方法,生成第三步的ServerBootstrapAcceptor,初始化处理新的子连接的channelReader的处理器。

 10.现在初始化和注册完成了,我们再回到第一步,进行doBind0(regFuture, channel, localAddress, promise)

AbstractBootstrap    
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()) {
                    channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    promise.setFailure(regFuture.cause());
                }
            }
        });
    }

11.channel.bind,会调用内部管道的bind,然后到tail的BIND,再到AbstractChannelHandlerContext的bind,因为tail就是继承于AbstractChannelHandlerContext,这里面的BIND就是从尾部向前找,找一个带有bind标签的HANDLER进行处理。最终找到了header.ChannelHandlerContext(DefaultChannelPipeline$HeadContext#0, [id: 0x159b9902])

    public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return pipeline.bind(localAddress, promise);
    }

    public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return tail.bind(localAddress, promise);
    }

public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
        ObjectUtil.checkNotNull(localAddress, "localAddress");
        if (isNotValidPromise(promise, false)) {
            // cancelled
            return promise;
        }

        final AbstractChannelHandlerContext next = findContextOutbound(MASK_BIND);
        EventExecutor executor = next.executor();
        next.invokeBind(localAddress, promise);
        return promise;
    }

12.最终到了head的BIND,这里面调用了unsafe本地IO类的bind.

   final class HeadContext extends AbstractChannelHandlerContext
            implements ChannelOutboundHandler, ChannelInboundHandler {
    
 @Override
        public void bind(
                ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
            unsafe.bind(localAddress, promise);
        }

13.最终调用到AbstractChannel的内部类AbstractUnsafe的bind,

   @Override
        public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
            boolean wasActive = isActive();
            try {
                doBind(localAddress);
            } catch (Throwable t) {
                safeSetFailure(promise, t);
                closeIfClosed();
                return;
            }

            if (!wasActive && isActive()) {
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.fireChannelActive();
                    }
                });
            }

            safeSetSuccess(promise);
        }

 14.接着调用到了AbstractUnsafe的外部类的继承类的doBind方法,也就是NioServerSOcketChannel.doBind,这个就是调用原生的ServeSocketChannel进行bind.


    protected void doBind(SocketAddress localAddress) throws Exception {
        if (PlatformDependent.javaVersion() >= 7) {
            javaChannel().bind(localAddress, config.getBacklog());
        } else {
            javaChannel().socket().bind(localAddress, config.getBacklog());
        }
    }

15.绑定成功后会调用pipeline.fireChannelActive();这个是从头节点一直向后传递事件。在头节点的

channelActive方法中会触发readIfIsAutoRead
      @Override
    public final ChannelPipeline fireChannelActive() {
        AbstractChannelHandlerContext.invokeChannelActive(head);
        return this;
    }

  static void invokeChannelActive(final AbstractChannelHandlerContext next) {
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeChannelActive();
        } else {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    next.invokeChannelActive();
                }
            });
        }
    }



   final class HeadContext extends AbstractChannelHandlerContext
            implements ChannelOutboundHandler, ChannelInboundHandler {

      @Override
        public void channelActive(ChannelHandlerContext ctx) {
            ctx.fireChannelActive();

            readIfIsAutoRead();
        }

 16.readIfIsAutoRead就是channel如果开启了自动读,则开始设置读关注事件到eventLoop的selector中。这个读会从管道的读-》tail的读->一直向前找支持读的handler进行处理。这个就是找到了head的handler

       private void readIfIsAutoRead() {
            if (channel.config().isAutoRead()) {
                channel.read();
            }
        }

 final class HeadContext extends AbstractChannelHandlerContext
            implements ChannelOutboundHandler, ChannelInboundHandler {

        public void read(ChannelHandlerContext ctx) {
            unsafe.beginRead();
        }

 17.headHandler的beginRead就调用了unsafe.beginRead方法,这个会调用外部channel.

doBeginRead--》AbstractNioChannel
AbstractNioChannel  
  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) {
            selectionKey.interestOps(interestOps | readInterestOp);
        }
    }

这个就是将读事件加到channel的selectKey的关注事件中。

 

 四、接收新连接流程

1.我们回到上一节的3,9步,为父类NioServerSocketChannel的管道中新增了一个handler,

ServerBootstrapAcceptor,用来处理父类的接收数据,也就是新连接请求。当有新连接进来时,会触发到ServerBootstrapAcceptor.channelRead

2.ServerBootstrapAcceptor.channelRead 方法是怎么被调用的呢? 其实当一个 client 连接到 server 时, Java 底层的 NIO ServerSocketChannel 会有一个 SelectionKey.OP_ACCEPT 就绪事件, 接着就会调用到 NioServerSocketChannel.doReadMessages:

NioServerSocketChannel  
protected int doReadMessages(List<Object> buf) throws Exception {
        SocketChannel ch = SocketUtils.accept(javaChannel());

        try {
            if (ch != null) {
                buf.add(new NioSocketChannel(this, ch));
                return 1;
            }
        } catch (Throwable t) {
            logger.warn("Failed to create a new channel from an accepted socket.", t);

            try {
                ch.close();
            } catch (Throwable t2) {
                logger.warn("Failed to close a socket.", t2);
            }
        }

        return 0;
    }

在 doReadMessages 中, 通过 javaChannel().accept() 获取到客户端新连接的 SocketChannel, 接着就实例化一个 NioSocketChannel, 并且传入 NioServerSocketChannel 对象(即 this), 由此可知, 我们创建的这个 NioSocketChannel 的父 Channel 就是 NioServerSocketChannel 实例 .

 3.ServerBootstrapAcceptor.channelRead方法,这个就是把子channel的管道添加子handler,并且把子channel注册到子group的eventLoop的selector中。流程跟父类channel注册一样。

  public void channelRead(ChannelHandlerContext ctx, Object msg) {
            final Channel child = (Channel) msg;
            child.pipeline().addLast(childHandler);
            setChannelOptions(child, childOptions, logger);
            setAttributes(child, childAttrs);
            try {
                childGroup.register(child)
        }

 4.还有个读完成事件,里面跟上一节的第16步一样,都是将当前channel的selectKey中加入读关注事件,以便接收读数据。

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) {
            ctx.fireChannelReadComplete();

            readIfIsAutoRead();
        }

 当然这个事件会反复调用,然后判断加过读事件,就不重复加了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值