Bootstrap

Netty中ServerBootstrap

ServerBootstrap是Netty中用于构建的服务器的引导类(辅助类),用于对服务器启动之前做一个配置,编程风格采用方法连的方式,优雅美观。

		ServerBootstrap bootstrap = new ServerBootstrap();
		EventLoopGroup parent = new NioEventLoopGroup();
		EventLoopGroup child = new NioEventLoopGroup();
		bootstrap.group(parent,child)//ServerBootstrap中的childGroup属性,以及超类AbstractBootstrap中group属性进行赋值
		.channel(NioServerSocketChannel.class)//对超类AbstractBootstrap中的channelFactory属性进行赋值
		.childHandler(new ChannelInitializer<Channel>() {//对ServerBootstrap中的childHandler属性进行赋值
			@Override
			protected void initChannel(Channel ch) throws Exception {
			}
		}).handler(null);对AbstractBootstrap中的handler属性进行赋值

下面我们对ServerBootstrap的bind()方法进行详细梳理:

查看源码,可以看出bind方法最关键的方法在于initAndRegister()方法:

    final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            channel = channelFactory.newChannel();//利用BootStrap中配置好的channelFactory根据Channel的类型实例化一个Channel.
            init(channel);//初始化实例化后的channel
        } catch (Throwable t) {
            if (channel != null) {
                // channel can be null if newChannel crashed (eg SocketException("too many open files"))
                //channel是可以为空的,如果newChannel方法抛出异常了,例如SocketException
                 channel.unsafe().closeForcibly();
                // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
                //当channel注册失败后,我们需要强制性的返回一个ChannelFuture,并设置标志值为failure
                  return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
            }
            // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
            //当channel不能注册,我们需要的返回一个ChannelFuture,传入一个FailedChannel,并设置标志值为failure
            return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
        }

        //这里就将channel注册到EventLoop当中。下面有源码解析。
        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }
        return regFuture;
    }

下面是init()方法的重要代码,用于给ChannelPipeline添加ChannelHandler.

        /**
         * 在channelpiple中添加可能存在的ChannelHandler
         * 使用channel的eventloop(其实也是执行器excutor)执行一个任务,
         * 任务的工作是给pipleline增加一个ServerBootstrapAcceptor的ChannelHandler,用于接收连接
         */
        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) throws Exception {
                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(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });

下面是initAndRegister()方法中将Channel注册到EventLoop中的源码解析

  • 调用config()方法获得BootStrap中获得一个完整的配置信息对象,通过group()方法获取EventLoopGroup对象
  • 调用group的register方法进行注册
    @Override
    public ChannelFuture register(Channel channel) {
         //next()方法会获取group当中的某一个EventLoop,然后调用EventLoop的register()方法
         return next().register(channel);
    }
  • 而我们在NioServerEventLoopGroup的时候,我们在给children赋予的EventLoop是NioEventLoop,所以将会调用NioEventLoop.register方法
    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
        return new NioEventLoop(this, executor, (SelectorProvider) args[0],
            ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
    }
    public void register(final SelectableChannel ch, final int interestOps, final NioTask<?> task) {
        //对一些值的判断,省略

        try {
             //这里就调用Java NIO中的API,用于注册该channel感兴趣的key
             ch.register(selector, interestOps, task);
        } catch (Exception e) {
            throw new EventLoopException("failed to register a channel", e);
        }
    }



;