netty服务端启动流程总结

参考资料

NioEventLoopGroup源码分析

netty服务端启动流程源码分析

先看个流程图

在这里插入图片描述

服务端启动做了哪些事情

//创建EventLoopGroup,初始化所有的EventLoop,初始化线程工具
 EventLoopGroup bossEventLoopGroup = new NioEventLoopGroup(2);
 executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
//创建channel,初始化channel的pipeline
channel = channelFactory.newChannel();
//为channel的pipeline绑定ChannelHandler----使用EventLoop(与channel关联的)异步执行
 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));
                    }
                });
            }
        });
//选择EventLoopGroup的一个EventLoop的selector,将channel注册上去
ChannelFuture regFuture = config().group().register(channel);
//将channel注册到一个绑定的EventLoop的selector----使用EventLoop(与channel关联的)异步执行
eventLoop.execute(new Runnable() {
    
    
  @Override
  public void run() {
    
    
    register0(promise);
  }
});
//绑定Channel到指定的端口-----使用EventLoop(与channel关联的)异步执行
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());
                }
            }
        });
    }
                

EventLoop的execute方法

//EventLoop的execute方法
public void execute(Runnable task) {
    
    
    if (task == null) {
    
    
        throw new NullPointerException("task");
    }

  	//判断当前EventLoop持有线程有没有启动
    boolean inEventLoop = inEventLoop();
  	//启动过,直接添加到任务队列
    if (inEventLoop) {
    
    
        addTask(task);
    } else {
    
    
        //没启动,先启动EventLoop唯一的线程,然后添加任务
        startThread();
        addTask(task);
        if (isShutdown() && removeTask(task)) {
    
    
            reject();
        }
    }

    if (!addTaskWakesUp && wakesUpForTask(task)) {
    
    
        wakeup(inEventLoop);
    }
}

EventLoop的轮训方法

//轮训处理方法
protected void run() {
    
    
    for (;;) {
    
    
        try {
    
    
            switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
    
    
            try {
    
    
                        processSelectedKeys();
                    } finally {
    
    
                        final long ioTime = System.nanoTime() - ioStartTime;
                        runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
                    }
                //省去......
                
//1.轮训方法会去task队列获取任务
//2.channel的pipeline绑定ChannelHandler,会在这里触发回调
//3.channel注册到一个绑定的EventLoop的selector,会在这里触发回调 
//4.Channel到指定的端口绑定,会在这里触发回调 
//5.上面2-4都是初始化异步做的事情,都丢到channel关联的EventLoop去做                

总结

1.启动流程中做的事情还是 创建selector,channel,绑定端口,轮训selector
  其实和我们使用jdk nio编写一个网络编程是没本质区别的,只不过是做了组件化
  的封装,扩展性更强
2.netty的EventLoop其实就像一个有一个线程的线程池,去轮训处理绑定在当前
 EventLoop的所有channel的所有提交的任务,EventLoop也有拒绝策略,线程
 工厂,任务队列等,只不过没有回收策略,这和他是一个具有NIO编程的强功能性
 相关,注定是个长任务,而且也就一个线程,所以没必要 

猜你喜欢

转载自blog.csdn.net/weixin_38312719/article/details/108548322