2019-05-16 netty 服务端启动

以netty源码中的为EchoServer例,分析netty服务端启动的流程

public final class EchoServer {

    public static void main(String[] args) throws Exception {
        // Configure the server.
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 100)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new LoggingHandler(LogLevel.INFO));
                            p.addLast(new EchoServerHandler());
                        }
                    });

            // Start the server.
            ChannelFuture f = b.bind(8007).sync();

            // Wait until the server socket is closed.
            f.channel().closeFuture().sync();
        } finally {
            // Shut down all event loops to terminate all threads.
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

首先在ServerBootstrap调用group方法的时候会传进去两组group线程组;


image.png

调用父类的构造器设置group属性


image.png

这两个group线程会分别赋给group和childGroup两个属性;


image.png
image.png
image.png

这里的childGroup 是由EventLoopGroup workerGroup = new NioEventLoopGroup()初始化的,默认会创建两倍cpu核数的NioEventLoop线程数量;

image.png

继续走调用channel()方法,会创建一个ReflectiveChannelFactory,这里传进去的就是class io.netty.channel.socket.nio.NioServerSocketChannel这个class;


image.png

同时设置channelFactory属性为为NioServerSocketChannel.class;


image.png

接下来就是设置一些属性,handler,childHandler,这里不再展开;

继续走,看调用bind方法的时候


image.png

最终会调用到io.netty.bootstrap.AbstractBootstrap#doBind方法


image.png

调用initAndRegister 初始化channel并且进行注册selector;
首先看初始化Channel部分,调用this.channelFactory.newChannel();方法


image.png
image.png

其实这里的clazz就是class io.netty.channel.socket.nio.NioServerSocketChannel,其实创建的channel对象就是NioServerSocketChannel;

接下来我们在看看NioServerSocketChannel的构造函数做了什么?

image.png
image.png

调用newSocket方法,通过jdk底层SelectorProvider.provider().openServerSocketChannel()来创建jdk ServerSocketChannel;

image.png

接下来调用构造函数初始化属性配置,其实就是设置ServerSocketChannelConfig


image.png

设置unsafe,id,pipeline等参数,其实在这里就已经确定了这个channel属于哪个pipeline; 客户端创建channel也是一样的;


image.png

初始化channel


image.png

配置config


image.png

以下便是这个config的属性配置


image.png

以上就是服务端channel的创建过程,接下来就是服务端channel的初始化过程
1.设置option属性值,把它设置到config中去


image.png
image.png

2.设置channel的attr属性


image.png

3.为pipeline设置handler,ChannelHandler handler = ServerBootstrap.this.config.handler();去除BootStrap中配置的handler,然后添加到Pipeline中

image.png

4.添加一个ServerBootstrapAcceptor,其实这是一个特殊的channelHandler,
传入的一个work线程组,handler,attr和options等属性;


image.png

channel注册到selector


image.png

this.config().group()这个其实就是boss线程绑定channel,代码位置io.netty.channel.AbstractChannel.AbstractUnsafe#register;

image.png

在看register0方法实现


image.png
image.png

调用jdk底层进行注册,每隔NioEventLoop都有一个Selector属性


image.png

结下来AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded();会调用到io.netty.channel.DefaultChannelPipeline.PendingHandlerAddedTask#execute从而会触发io.netty.channel.ChannelHandlerAdapter#handlerAdded方法的调用

这行代码AbstractChannel.this.pipeline.fireChannelRegistered();会触发
io.netty.channel.ChannelInboundHandler#channelRegistered事件的调用;

继续看doBind方法


image.png

io.netty.channel.AbstractChannel.AbstractUnsafe#bind


image.png

最终通过NioServerSocketChannel 进行端口绑定,调用jdk底层的方法


image.png

最后触发ChannelActive事件,调用readIfIsAutoRead()方法处理客户端链接事件

image.png

感兴趣的可以去跟下代码,这个read会在pipeline上不断的传播


image.png

有一个自动读的配置其实是在初始化ServerBootstrapAcceptor配置的


image.png
image.png
image.png

这里的readInterestOp 其实就是NioServerSocketChannel构造函数中传入的16


image.png

到此,服务端启动的代码走读就完了。

你可能感兴趣的:(2019-05-16 netty 服务端启动)