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

参考资料

NioEventLoopGroup源码分析

启动作用

1.和普通我们写JKD Nio的程序是一样,只是做了组件上的封装
2.首先是创建NioServerSocketChannel,注册到对应的NioEventLoop上
  ,启动一个线程,扫描NioEventLoop的Selector的连接事件
3.然后将NioServerSocketChannel绑定到对应端口

示例

//创建两个EventLoopGroup,一个用于连接处理,一个用于IO读写事件处理
EventLoopGroup bossEventLoopGroup = new NioEventLoopGroup(2);
EventLoopGroup workEventExecutors = new NioEventLoopGroup(2);

//创建启动类对象
ServerBootstrap serverBootstrap=new ServerBootstrap();

try {
    
    
  //设置EventLoopGroup
    serverBootstrap.group(bossEventLoopGroup, workEventExecutors)
      		  //设置服务端使用的Channel,不同协议服务端使用不同的通道
            .channel(NioServerSocketChannel.class)
      			//绑定端口
            .localAddress(port)
      			//设置子channel使用的处理器
      			//处理连接的通道叫父通道,处理传输的通道叫子通道
            //相应的处理器也叫父处理器和子处理器,这里是childHandler
            .childHandler(new ChannelInitializer<SocketChannel>() {
    
    
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
    
    
                    socketChannel.pipeline().addLast(new MyHandler());
                }
            });

    //所有参数都构建完毕,开始绑定,真正启动服务,也是我们分析的入口bind方法
    ChannelFuture sync = serverBootstrap.bind().sync();

    ChannelFuture channelFuture = sync.channel().closeFuture();
    channelFuture.sync();
    System.out.println("服务启动成功");
}catch (Exception e){
    
    
    bossEventLoopGroup.shutdownGracefully();
    workEventExecutors.shutdownGracefully();
}

ServerBootstrap的属性简单介绍

//ServerBootstrap关键属性

//处理IO事件的事件循环组
private volatile EventLoopGroup childGroup;
处理IO事件的处理器的辅助器
private volatile ChannelHandler childHandler;

//ServerBootstrap父类

//处理连接事件的事件循环组
volatile EventLoopGroup group;
//用于反射创建Channel的工厂
private volatile ChannelFactory<? extends C> channelFactory;
//处理连接事件的处理器的辅助器
private volatile ChannelHandler handler;

bind方法分析

//在bind直接调用的方法
private ChannelFuture doBind(final SocketAddress localAddress) {
    
    
  			//启动服务主流程
  			//1.做些初始化工作
  			//2.创建channel,将channel注册到NioEventLoop上去,开启NioEventLoop的轮训(启动线程)
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        //非主流程代码省去
        .....
        //绑定到对应的端口,这里操作简单,直接使用jdk底层绑定操作
		doBind0(regFuture, channel, localAddress, promise);	
    }

initAndRegister方法

final ChannelFuture initAndRegister() {
    
    
    Channel channel = null;
    try {
    
    
        //使用channelFactory反射创建通道,使用初始化的NioServerSocketChannel.class
        channel = channelFactory.newChannel();
      	//初始化通道
        init(channel);
    } catch (Throwable t) {
    
    
       //省去....
    }
		//1.将通道注册到NioEventLoopGroup中的某个NioEventLoop
  	//2.启动NioEventLoop绑定的线程,开始轮训监听连接事件
    //3.注意这里是group,而不是childGroup的某个NioEventLoop
    ChannelFuture regFuture = config().group().register(channel);
    if (regFuture.cause() != null) {
    
    
        if (channel.isRegistered()) {
    
    
            channel.close();
        } else {
    
    
            channel.unsafe().closeForcibly();
        }
    }
    return regFuture;
}

newChannel方法

//构建ServerBootstrap的channel的时候,初始化了这个工厂
channel = channelFactory.newChannel();

//ServerBootstrap类
//构建ServerBootstrap的channel代码
public B channel(Class<? extends C> channelClass) {
    
    
        if (channelClass == null) {
    
    
            throw new NullPointerException("channelClass");
        }
  			//使用class属性构建的一个工厂
        return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
    }

//ReflectiveChannelFactory类
//工厂使用class反射创建通道
@Override
    public T newChannel() {
    
    
        try {
    
    
            return clazz.getConstructor().newInstance();
        } catch (Throwable t) {
    
    
            throw new ChannelException("Unable to create Channel from class " + clazz, t);
        }
    }

init(channel)方法

//初始化通道一些信息,options(通道选项参数),ChannelPipeline(通道处理器链)
void init(Channel channel) throws Exception {
    
    
    //将构建ServerBootstrap给的option参数赋值给channel
    final Map<ChannelOption<?>, Object> options = options0();
    synchronized (options) {
    
    
        setChannelOptions(channel, options, logger);
    }
    //省去不关心代码...

  	//获取到channel的处理器流,在实例化channel的时候,构造给了DefaultChannelPipeline
  	//ChannelPipeline是执行处理器链,专门用来处理IO事件的,这里先不关心
  	//我们只需要知道,一个channel会有一个ChannelPipeline,ChannelPipeline上绑定了
  	//一些处理器就好了
    ChannelPipeline p = channel.pipeline();
		//省去不关心代码...
    
    //先将包装好的ChannelHandle存起来,后面使用
  
  	//为ChannelPipeline绑定ChannelHandle
  	//这里只是绑定了ChannelInitializer,这是个特殊的ChannelHandlC
  	//ChannelInitializer是真正的ChannelHandle的包装,里面放了我们自己构建ServerBootstrap
    //时候,真正的ChannelHandle,后面启动服务有一个动作,就是解析出我们自己添加的ChannelHandle
    p.addLast(new ChannelInitializer<Channel>() {
    
    
        @Override
        public void initChannel(final Channel ch) throws Exception {
    
    
            final ChannelPipeline pipeline = ch.pipeline();
          	//config持有ServerBootstrap引用,里面有我们传的handler
            //这里handle是父通道的ChannelHandle,一般我们不设置,但是有助于我们了解
            //子通道的ChannelHandle,原理是一样的
            ChannelHandler handler = config.handler();
            if (handler != null) {
    
    
                pipeline.addLast(handler);
            }
						//父通道一般是使用ServerBootstrapAcceptor,也就是Reactor的Acceptor
          	//我们一般不需要设置父通道的ChannelHandle的原因,这里会给默认加上
          	//因为父通道处理器做的事情是固定的,一般不需要我们自定义,不像子通道的处理器一样
          	//需要自定义我们自己的操作
            ch.eventLoop().execute(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    pipeline.addLast(new ServerBootstrapAcceptor(
                            ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                }
            });
        }
    });
}

register(channel)

//将通道注册到NioEventLoopGroup的一个NioEventLoop(Reactor)上的Selector上去
ChannelFuture regFuture = config().group().register(channel)
//MultithreadEventLoopGroup类
  
@Override
    public ChannelFuture register(Channel channel) {
    
    
  			//选择其中一个NioEventLoop,注册上去
        return next().register(channel);
    }  

//MultithreadEventExecutorGroup类

//调用PowerOfTwoEventExecutorChooser或者GenericEventExecutorChooser获取一个NioEventLoop
@Override
    public EventExecutor next() {
    
    
        return chooser.next();
   }

//SingleThreadEventLoop类
//下面是NioEventLoop的register方法
 @Override
    public ChannelFuture register(Channel channel) {
    
    
        //1.将channel包装为一个DefaultChannelPromise对象
      	//2.后续直接使用DefaultChannelPromise,这样可以获取channel,也能获得channel所在的
      	//NioEventLoop的相关信息
        return register(new DefaultChannelPromise(channel, this));
    }

    @Override
    public ChannelFuture register(final ChannelPromise promise) {
    
    
        ObjectUtil.checkNotNull(promise, "promise");
        //1.获取通道channel,然后注册到相应的this(NioEventLoop)上去
      	//2.unsafe对象是构建channel时候创建的,unsafe主要作用是包装JDK的NIO操作
        promise.channel().unsafe().register(this, promise);
        return promise;
    }

//AbstractUnsafe类
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    
    
           //省去不需要代码..
  	       
            AbstractChannel.this.eventLoop = eventLoop;

  					//判断当前NioEventLoop的轮训线程是否启动,分两种情况
  					//1.启动过,那么直接注册
  					//2.没启动过,先启动线程,然后注册register0
            if (eventLoop.inEventLoop()) {
    
    
                register0(promise);
            } else {
    
    
              //启动NioEventLoop的线程,注册任务传递
              eventLoop.execute(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                  register0(promise);
                }
              });    
        }

NioEventLoop的execute方法

//SingleThreadEventExecutor类(父类)
//启动NioEventLoop线程
public void execute(Runnable task) {
    
    
    if (task == null) {
    
    
        throw new NullPointerException("task");
    }

    boolean inEventLoop = inEventLoop();
    //是否启动过线程两种情况
    //1.启动过,那么直接将任务添加到队列
  	//2.没启动过,那么启动一个线程,并且将任务添加到队列中
    if (inEventLoop) {
    
    
        addTask(task);
    } else {
    
    
      //启动线程
        startThread();
        addTask(task);
        if (isShutdown() && removeTask(task)) {
    
    
            reject();
        }
    }
}

//启动线程
private void startThread() {
    
    
        if (state == ST_NOT_STARTED) {
    
    
            if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
    
    
                doStartThread();
            }
        }
 }

//使用线程工具executor启动一个线程
private void doStartThread() {
    
    
  assert thread == null;
  executor.execute(new Runnable() {
    
    
    @Override
    public void run() {
    
    
      thread = Thread.currentThread();
      if (interrupted) {
    
    
        thread.interrupt();
      }

      //省去.....
      
      //执行轮训方法
      SingleThreadEventExecutor.this.run();

      //省去.....
    }
  }
}

 //轮训方法,这里会获取队列任务进行执行
 //1.比如回调上面的register0(promise);,会取出任务,然后将channel注册到selector上
 //2.轮训获取连接任务,然后使用连接处理器连接                  
 @Override
    protected void run() {
    
    
        for (;;) {
    
    
            try {
    
    
                switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
    
    
                    case SelectStrategy.CONTINUE:
                        continue;
                    case SelectStrategy.SELECT:
                        select(wakenUp.getAndSet(false));

                        if (wakenUp.get()) {
    
    
                            selector.wakeup();
                        }
                        // fall through
                    default:
                }

                cancelledKeys = 0;
                needsToSelectAgain = false;
                final int ioRatio = this.ioRatio;
                if (ioRatio == 100) {
    
    
                    try {
    
    
                        processSelectedKeys();
                    } finally {
    
    
                        // Ensure we always run tasks.
                        runAllTasks();
                    }
                } else {
    
    
                    final long ioStartTime = System.nanoTime();
                    try {
    
    
                        processSelectedKeys();
                    } finally {
    
    
                        // Ensure we always run tasks.
                        final long ioTime = System.nanoTime() - ioStartTime;
                        runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
                    }
                }
            } catch (Throwable t) {
    
    
                handleLoopException(t);
            }
            // Always handle shutdown even if the loop processing threw an exception.
            try {
    
    
                if (isShuttingDown()) {
    
    
                    closeAll();
                    if (confirmShutdown()) {
    
    
                        return;
                    }
                }
            } catch (Throwable t) {
    
    
                handleLoopException(t);
            }
        }
    }                   

总结

1.本节主要是探索服务端怎么运行起来的,怎么绑定一个NioEventLoop,然后工作起来的一个流程
2.下面章节还需要分析轮训里面具体做了一些什么,channel,NioEventLoop,handle,连接处理器接受连接等的细节

猜你喜欢

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