一、启动类
启动类分为服务端和客户端两种,第一节中,netty通过ServerBootstrap启动类来启动服务端程序(客户端用Bootstrap),其它的都是通过参数设置来配置到启动类里:
- group():配置工作线程组
- channel():传入channel,是OIO还是NIO,这里需要跟group相对应。
- localAddress():传入绑定的地址、端口
- childHandler():具体业务逻辑是在handler中
- bind():端口的绑定
从第一节中可知,端口绑定完成,服务就已经启动,系统就可以接收客户端的请求,开始工作。这些工作都是通过ServerBootstrap来完成的,具体它是怎么做到的?我们先自顶向下依次分析每个方法具体做什么。
- group():查看方法源码可知主要是设置group和childGroup两个属性
- channel():设置this.channelFactory属性,并把channel的参数值作为构造方法传入channelFactory
- localAddress():设置localAddress属性
- childHandler():设置childHandler属性
- bind():具体的端口绑定方法入口,实现在父类AbstractBootstrap中。
父类AbstractBootstrap中属性有:group、channelFactory、localAddress、handler、options、attrs、EMPTY_OPTION_ARRAY、EMPTY_ATTRIBUTE_ARRAY。
ServerBootstrap中的属性有:childOptions、childAttrs、config、childGroup、childHandler。具体每个属性的作用,在源码中进行分析。
从源码来看bind方法是端口绑定的入口方法,所以我们先跟着这个方法一点点来分析。
bind()–>doBind(final SocketAddress localAddress)doBind()的源码如下。
private ChannelFuture doBind(final SocketAddress localAddress) {
//这里我们省略了大部分代码,后续的分析当中我们也会进行代码的省略,只关注重点部分
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
doBind0(regFuture, channel, localAddress, promise);
}
doBind会调用initAndRegister()和最终的doBind0()方法,initAndRegister和doBind0又分别做了什么?
- initAndRegister()主要做三件事:
1、实例化channel:通过配置的channelFactory,利用反射来实例化channel对象
2、初始化channel:init(channel)是一个抽象方法,具体的实现实在ServerBootstrap中。这个方法就是把ServerBootstrap设置的属性和options信息配置到channel上,然后往channel的pipeline属性中添加启动类中的一个内部类(ServerBootstrapAcceptor这是专门用来处理客户端连接请求的handler)
3、注册channel:就是把当前的channel作为附件注册到selector上,注册是通过EventLoopGroup类实现的。具体过程,在分析EventLoopGroup的时候再详细说明。
final ChannelFuture initAndRegister() {
Channel channel = channelFactory.newChannel();//实例化通过 channel()配置的class,就是通过调用channel的构造方法实例化具体的channel
init(channel);//初始化channel。
ChannelFuture regFuture = config().group().register(channel);//注册channel
return regFuture;
}
- doBind0():这个方法只做一件事,就是调用NIO底层的channel绑定对应的端口,端口绑定完成就开始等待客户端的链接请求。
以上,有任何不对的地方,请指正,敬请谅解。