netty源码分析之-服务端启动核心源码分析(5)

来源:互联网 发布:淘宝店铺查询 编辑:程序博客网 时间:2024/05/22 03:50

对于netty中服务端启动的核心流程分析

ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
    /**     * Create a new {@link Channel} and bind it.     */    public ChannelFuture bind(int inetPort) {        return bind(new InetSocketAddress(inetPort));    }

可以追溯到如下具体实现:

private ChannelFuture doBind(final SocketAddress localAddress) {        final ChannelFuture regFuture = initAndRegister();   ①        final Channel channel = regFuture.channel();        if (regFuture.cause() != null) {            return regFuture;        }        if (regFuture.isDone()) {            // At this point we know that the registration was complete and successful.            ChannelPromise promise = channel.newPromise();            doBind0(regFuture, channel, localAddress, promise);  ②            return promise;        } else {            // Registration future is almost always fulfilled already, but just in case it's not.            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) {                        // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an                        // IllegalStateException once we try to access the EventLoop of the Channel.                        promise.setFailure(cause);                    } else {                        // Registration was successful, so set the correct executor to use.                        // See https://github.com/netty/netty/issues/2586                        promise.registered();                        doBind0(regFuture, channel, localAddress, promise);                    }                }            });            return promise;        }    }
  • ① 对于initAndRegister()方法实现的核心代码:
Channel channel = null;channel = channelFactory.newChannel();init(channel);

channelFactory是AbstractBootstrap中持有的成员变量,是我们之前执行:

serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)

进行赋值的,也就是调用来之前分析的关于反射的部分,调用默认的无参构造方法生成对象,也就是:

private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();...public NioServerSocketChannel() {        this(newSocket(DEFAULT_SELECTOR_PROVIDER));    }...private static ServerSocketChannel newSocket(SelectorProvider provider) {        try {            /**             *  Use the {@link SelectorProvider} to open {@link SocketChannel} and so remove condition in             *  {@link SelectorProvider#provider()} which is called by each ServerSocketChannel.open() otherwise.             *             *  See <a href="https://github.com/netty/netty/issues/2308">#2308</a>.             */            return provider.openServerSocketChannel();        } catch (IOException e) {            throw new ChannelException(                    "Failed to open a server socket.", e);        }    }

通过SelectorProvider打开一个SocketChannel通道,openServerSocketChannel是对SocketChannel.open()方法阻塞上的一个优化

对于init(channel)的实现关键代码:

        ...        ChannelPipeline p = channel.pipeline();        ...        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));                    }                });            }        });        ...

该方法主要对ServerBootstrap进行成员变量的一些赋值,同时如果有调用.handle()方法,会在ChannelPipeline后面添加该ChannelInitializer的实现。

  • 对于doBind0(regFuture, channel, localAddress, promise)实现:
private static void doBind0(            final ChannelFuture regFuture, final Channel channel,            final SocketAddress localAddress, final ChannelPromise promise) {        // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up        // the pipeline in its channelRegistered() implementation.        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());                }            }        });    }

该方法在channelRegistered触发之前被调用可以去设置pipeline

ChannelFutureListener CLOSE_ON_FAILURE = new ChannelFutureListener() {        @Override        public void operationComplete(ChannelFuture future) {            if (!future.isSuccess()) {                future.channel().close();            }        }    };

添加的监听器表示当操作结束,但是并不是成功执行完的时候关闭这个Channel。因为这些方法是ChannelFuture.isDone()之后执行的,需要有结束的工作来处理一些资源,采用监听器就能够很好的做到这一点。

原创粉丝点击