netty启动流程

一、netty服务端代码

public class NettyServerExample {
    public static void main(String[] args) {
        //第一步1:定义两个eventLoopGroup
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        //第二步2-1:定义bootStrap
        ServerBootstrap bootstrap = new ServerBootstrap();
        
        bootstrap.group(bossGroup, workerGroup);
        bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
        bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
        bootstrap.channel(NioServerSocketChannel.class);
        //第二步2-2:定义bossGroup对应的handler
        bootstrap.handler(new FinalChannelEventHandler());
        //第二步2-3:定义workerGroup对应的handler
        FinalChannelEventHandler finalChannelEventHandler = new FinalChannelEventHandler();

        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch){
                ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                ch.pipeline().addLast(new IdleStateHandler(0, 0, 5000, TimeUnit.MILLISECONDS));
                ch.pipeline().addLast(finalChannelEventHandler);
            }
        });

        //第三步3:绑定端口
        bootstrap.bind(12345).syncUninterruptibly();
    }
    
    @ChannelHandler.Sharable
    private static class FinalChannelEventHandler extends  SimpleChannelInboundHandler<Object>{
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, Object data) {
            String s = ((ByteBuf) data).toString(CharsetUtil.UTF_8);
            ByteBuf message = Unpooled.buffer(s.length());
            message.writeBytes(s.getBytes(StandardCharsets.UTF_8));
            ctx.channel().writeAndFlush(message);
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) {
            System.out.println("final inactive...");
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx){
            System.out.println("final active...");
        }

        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt){
            System.out.println("trigger: " + evt);
        }
    }
}

二、EventGroup初始化

 从类继承和实现上看,NioEventLoopGroup实现了一个类似线程池的功能,随着代码一路跟踪下来,我们着重来看下MultithreadEventExecutorGroup这类的构造方法

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args)

protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
        checkPositive(nThreads, "nThreads");

        if (executor == null) {
            //线程池,自定义线程生成FastThreadLocalThread
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }

        //线程组,eventLoopGroup线程池组包含多个eventLoop线程池
        children = new EventExecutor[nThreads];

        for (int i = 0; i < nThreads; i ++) {
            boolean success = false;
            try {
                //生成的每个eventLoop,相当于只有一个核心线程,Integer.MAX_VALUE队列的线程池
                children[i] = newChild(executor, args);
                success = true;
            } catch (Exception e) {
                // TODO: Think about if this is a good exception type
                throw new IllegalStateException("failed to create a child event loop", e);
            } finally {
                if (!success) {
                    for (int j = 0; j < i; j ++) {
                        children[j].shutdownGracefully();
                    }

                    for (int j = 0; j < i; j ++) {
                        EventExecutor e = children[j];
                        try {
                            while (!e.isTerminated()) {
                                e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                            }
                        } catch (InterruptedException interrupted) {
                            // Let the caller handle the interruption.
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
            }
        }

        chooser = chooserFactory.newChooser(children);

        final FutureListener<Object> terminationListener = new FutureListener<Object>() {
            @Override
            public void operationComplete(Future<Object> future) throws Exception {
                if (terminatedChildren.incrementAndGet() == children.length) {
                    terminationFuture.setSuccess(null);
                }
            }
        };

        for (EventExecutor e: children) {
            e.terminationFuture().addListener(terminationListener);
        }

        Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
        Collections.addAll(childrenSet, children);
        readonlyChildren = Collections.unmodifiableSet(childrenSet);
    }

四个入参:

1.线程数设置0则为当前cpu core * 2

2.设置默认值为ThreadPerTaskExecutor线程池,使用FastThreadLocalRunnable生成线程执行任务

3.选择NioEventLoop的策略,2的n次方 与,非2的n次方 求余

executors[idx.getAndIncrement() & executors.length - 1]                    与运算速度快

executors[(int) Math.abs(idx.getAndIncrement() % executors.length)]

4.args中包含三块:1.Selector 2.选择策略(select.selctNow()) 3.线程池拒绝策略(默认大小是Integer.MAX_VALUE)

三、ServerBootStrap初始化

1.一个是bossGroup绑定的handler,绑定时端口时初始化一次(后面绑定讲解)

2.一个是workerGroup绑定的handler,每次新连接初始化一次

四、端口绑定

AbstractBootstrap的doBind方法

private ChannelFuture doBind(final SocketAddress localAddress) {
        //初始化和注册,包装了nio的注册;异步处理
        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;
        }
    }

AbstractBootstrap的initAndRegister

final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            //反射初始化SelectorProvider.provider().openServerSocketChannel()
            channel = channelFactory.newChannel();
            //初始化
            init(channel);
        } catch (Throwable t) {
            if (channel != null) {
                // channel can be null if newChannel crashed (eg SocketException("too many open files"))
                channel.unsafe().closeForcibly();
                // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
                return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
            }
            // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
            return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
        }

        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }

        return regFuture;
    }

ServerBootstrap的init方法

   void init(Channel channel) {
        setChannelOptions(channel, newOptionsArray(), logger);
        setAttributes(channel, newAttributesArray());

        ChannelPipeline p = channel.pipeline();

        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);

        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();
                //这个地方是之前绑定只初始化一次bossGroup的handler的
                if (handler != null) {
                    pipeline.addLast(handler);
                }

                //客户端连接服务端成功后,服务端accept后新建一个socketChannel将读写注册到workGroup中,ServerBootstrapAcceptor这个类中处理
                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

ServerBootstrapAcceptor的channelRead

        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            //accept的socketChannel,后续注册读写事件
            final Channel child = (Channel) msg;
            //新连接的socketChannel中每次在pipeline中新增childHandler
            child.pipeline().addLast(childHandler);

            setChannelOptions(child, childOptions, logger);
            setAttributes(child, childAttrs);

            try {
                childGroup.register(child).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (!future.isSuccess()) {
                            forceClose(child, future.cause());
                        }
                    }
                });
            } catch (Throwable t) {
                forceClose(child, t);
            }
        }

NioServerSocketChannel的doReadMessages,serverBootstrap初始化时指定的bootstrap.channel(NioServerSocketChannel.class)

接下来看AbstractBootstrap中的dobind0方法

    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.
        //bossGroup的eventLoop直接启动线程,只需要绑定一次
        channel.eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                if (regFuture.isSuccess()) {
                    //javaChannel().bind(localAddress, config.getBacklog())进行绑定
                    channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    promise.setFailure(regFuture.cause());
                }
            }
        });
    }

二、总结

1.启动过程中会产生一些异步事件,比如register,bind等,根据eventLoop.inEventLoop()判断当前程序执行的线程和首个启动eventLoop保存在其中的线程是否一致。一致直接执行,不一致扔进这个方法通常用于判断当前线程是否可以直接执行某些操作,以避免线程切换带来的性能损失。

2.eventLoopGroup可以理解为线程池的一个组,每个连接socketChannel从中获取一个线程池eventLoop;其中,一个连接只能对应一个线程池,一个线程池可以处理多个连接;eventLoop是个单线程+队列(默认Integer.MAX_VALUE)+拒绝策略。

3.bossGroup线程池一般是1,workerGroup默认是cpu core*2;bossGroup监听连接事件,accept后立刻注册到workerGroup上;类似经典的reactor模型中的多线程模型。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值