Netty服务端启动分为四个过程,创建服务端Channel,初始化服务端Channel,注册selector,端口绑定。
创建服务端Channel过程
从bind进入源码
调用doBind方法,进入initAndRegister()方法
调用channelFactory的newChannel方法来创建我们服务端的Channel
进入newChannel方法,发现通过反射来创建channel,用Class类的newInstance,那么查看class类到底是什么,我们来查看channelFactory是在哪初始化的,从channel进入
将channelClass通过反射创建ReflectiveChannelFactory,这个channelClass就是我们传进来的NioServerSocketChannel.class,通过反射来调用各个函数,我们来看下服务端NioServerSocketChannel.class
1 | public B channel(Class<? extends C> channelClass) { |
反射创建服务端Channel
newSocket
我们进入NioServerSocketChannel.class,这是他的一个构造函数,通过newSocket来创建jdk底层的channel,我们进入newSocket方法
通过jdk底层的openServerSocketChannel方法去创建服务端的ServerSocketChannel,进入ServerSocketChannel
这个ServerSocketChannel是jdk底层的java.nio.channels,这是就把服务端的channel创建完毕了
NioServerSocketChannelConfig
config主要目的就是后续对channel的tcp底层参数access操作时,是通过config来配置
AbstractNioChannel
configureBlocking(false)
我们进入NioServerSocketChannel的super类里,在向上super类中
ch.configureBlocking(false)设置服务端channel为非阻塞
AbstractChannel
调用AbstractChannel来创建id(channel的唯一标识),unsafe(channel底层的tcp读写的类),pipeline,
初始化服务端Channel
我们创建过服务端的Channel后就开始初始化Channel
初始化服务端Channel需要以下几个步骤
我们继续从bind方法入口知道进入初始化和登陆initAndRegister方法
进入到ServerBootstrap的init方法,ChannelOptions,ChannelAttrs这两个过程就是把用户自定义的一些属性给它保存起来,然后是ChildOptions和ChildAttrs
ChildOptions和ChildAttrs也是保存起来,保存到currentChildOptions和currentChildAttrs里
通过pipeline的addLast方法,把逻辑链物理链添加进去
初始化服务端Channel就是保存用户自定义的属性,用这些属性创建连接接入器。连接接入器每次acceptor新的连接后,都会使用这些属性对连接做配置,
注册selector
当我们创建以及初始化后,就开始注册channel
注册selector入口就是调用AbstractChannel.register方法首先把定义的NIO线程和当前的channel绑定,接下来调用register做实际的注册,实际注册过程分三个过程,调用jdk底层注册。进入initAndRegister方法,我们可以看到register方法,进入AbstractChannel的register方法
其中的AbstractChannel.this.eventLoop = eventLoop告诉Channel后续所有事件的io操作都交给eventLoop来处理,接下来会调用register0方法
register0就是做的实际注册,它主要做了这些事情,doRegister,触发一个fireChannelRegistered事件,我们主要赶猪doRegister方法,进入AbstractNioChannel的doRegister方法
javaChannel就是jdk底层创建的channel,调用其bind方法,当端口绑定完成后,会触发一个active事件,这个active事件最终会调用一个channel的read事件,read对服务端channel来说就是可以读了,可以读给新的连接
服务端口绑定
进入doBind方法,创建,初始化,注册后,开始doBind方法,进入doBind0方法,是AbstractChannel的bind方法,
这个bind方法主要做两件事情,一个是jdk底层的bind,然后调用fireChannelActive去触发ChannelActive的事件,我们进入doBind方法,在NioServerSocketChannel的doBind方法,
会调用javaChannel的bind方法,把一个端口进行绑定,这个javaChannel就是我们之前创建NioServerSocketChannel的时候创建的一个jdk底层的channel。而上面的wasActive刚开始是false,当端口绑定后返回true,
1 | if(!wasActive&&AbstractChannel.this.isActive)就是绑定前不是active,绑定后是active,这时调用fireChannelActive事件 |
服务端启动总结
首先调用newChannel来创建服务端的channel,过程就是调用jdk底层的API来创建jdk的channel,然后Netty将其包装成自己的服务端channel,同时会创建一些基本的组件绑定在channel上,比如pipline,然后调用init方法,初始化服务端channel,为服务端channel添加一个连接处理器,随后,调用register方法注册selector,Netty将jdk底层的channel注册到事件selector中去,并把Netty的服务端channel作为一个绑定到jdk底层的channel,最后调用doBind方法,调用jdk底层的API,实现对本地端口的监听,Netty会重新向select注册一个opselect事件,这样Netty就可以接受新的连接了