首先是启动main方法,在启动main方法时,有一个bind方法被调用,这里就是启动的重头戏
首先是io.netty.bootstrap.AbstractBootstrap#bind(int)
这里面首先会先校验,服务端主要校验group,childGroup是否存在、ChannelFactory是否存在以及ChildrenHandler是否存在
然后进入doBind()方法,会发现主要包含两块内容initAndRegister和doBind0,对应了启动的三个重要操作:初始化channel、注册channel注册到eventLoopGroup、绑定端口地址,下面让我们看具体是怎么实现的
首先进入initAndRegister,主要有两部分内容,生成一个channel,初始化这个channel,并将它绑定到某个地方
构建channel
我们在启动ServerBootstrap时设置的channel是NioServerSocketChannel,因此这里channel =channelFactory.newChannel();会生成一条NioServerSocketChannel,这个channel使用的是java的ServerSocketChannel,它感兴趣的事件是OP_ACCEPT,用来接收请求
我们顺着NioServerSocketChannel的构造函数往里看,调用io.netty.channel.socket.nio.NioServerSocketChannel#newSocket方法获取jdk的ServerSocketChannel,
调用父类的构造函数,设置感兴趣的时间是OP_ACCEPT
在父类AbstractChannel的构造函数里,构造了id、unsafe、pipeline,unsafe、pipeline这两个组件是netty里很重要的两个组件,这里先不详述unsafe、pipeline这两个组件是干嘛用的
init
创建channel后执行init,用来设置options参数、attrs参数,children的options参数、attrs参数,然后添加一个连接接收器
register
执行完初始化之后就开始注册,将这个channel注册到设置的EventLoopGroup上,进入发现调用channel的unsafe的register,这里会真正把channel注册到java的selector上,然后会invokeHandlerAdded、fireChannelRegistered
注册的时候会调用eventLoop.inEventLoop()判断当前县城是否和注册传入的eventLoop是同一个县城,如果是,就会立即执行真正的注册操作,如果不是,会调用execute放在eventLoop的县城里执行真正的注册操作
我们是从main方法里进来的,所以肯定不是eventLoop的县城,因此,在这里注册了一个任务,执行真正的注册操作
io.netty.channel.AbstractChannel.AbstractUnsafe#register0的操作一共包含一下几步
1、doRegister
往java的channel上注册selector,注意,这里感兴趣的事件是0,说明这里是不处理连接的接入的
2、pipeline.invokeHandlerAddedIfNeeded
调用实现
3、pipeline.fireChannelRegistered
同上
4、pipeline.fireChannelActive
这个调用的前提是isActive返回是true,正常情况下不会在这里被调到
bind
然后io.netty.bootstrap.AbstractBootstrap#doBind0绑定
这里的绑定最终会调到io.netty.channel.AbstractChannel.AbstractUnsafe#bind,这里利用多态调用到子类的实现,实际执行的是io.netty.channel.socket.nio.NioServerSocketChannel#doBind
io.netty.channel.socket.nio.NioServerSocketChannel#doBind将channel绑定到设置的端口上
channel绑定到设置的端口上之后,isActive返回是true了,这时就调用了fireChannelActive,还记的前面说的selector注册到channel的时候感兴趣的事件是0吗,没错就是在这里设置成OP_ACCEPT,fireChannelActive之后会调用到io.netty.channel.nio.AbstractNioChannel#doBeginRead,在这里把channel感兴趣的事件设置成了OP_ACCEPT
总结
1、启动的流程主要分为3步,init、register、bind
2、selector第一次注册到channel时,设置的感兴趣的事件是0,等到端口绑定好之后,才设置OP_ACCEPT
3、创建channel的时候,创建了两个重要的组件,unsafe、pipeline