大纲
1.服务端启动整体流程及关键方法
2.服务端启动的核心步骤
3.创建服务端Channel的源码
4.初始化服务端Channel的源码
5.注册服务端Channel的源码
6.绑定服务端端口的源码
7.服务端启动流程源码总结
1.服务端启动整体流程及关键方法
(1)关键方法
(2)整体流程
(1)关键方法
一.EventLoopGroup
服务端的线程模型外观类,Netty的线程模型是事件驱动的。也就是说,这个线程要做的事情就是不停地检测IO事件、处理IO事件、执行任务,并且不断重复这三个步骤。
二.ServerBootstrap
服务端的一个启动辅助类,通过给它设置一系列参数来绑定端口启动服务。
三.group(bossGroup, workerGroup)
设置服务端的线程模型,bossGroup的作用就是不断接收新的连接,并将新连接交给workerGroup来进行处理。
四.channel(NioServerSocketChannel.class)
设置服务端的IO类型为NIO,Netty是通过指定Channel的类型来指定IO类型的。Channel是Netty的一大组件,一个Channel就是一个连接或者一个服务端的bind动作。
五.handler()
表示在服务端的启动过程中,需要经过哪些流程。
六.childHandler()
设置ChannleHandler来处理每个连接上的数据。
七.ChannelFuture f = b.bind(8888).sync()
绑定端口并进行同步等待。绑定端口8888,等服务端启动完毕,才会进入下一行代码。
八.f.channel().closeFuture().sync()
等待服务端关闭端口绑定,这里的作用其实就是让程序不会退出。
九.bossGroup.shutdownGracefully()
关闭事件循环,关闭之后,main方法就结束了。
(2)整体流程
一.创建ServerBootstrap实例
ServerBootstrap是Netty服务端的启动辅助类,它提供了一系列方法用于设置服务端启动相关的参数。底层通过门面模式对各种能力进行抽象和封装,以让用户少和底层API交互,降低开发难度。ServerBootstrap只有一个无参的构造函数,它使用了Builder模式来处理参数过多的问题。
二.设置并绑定Reactor线程池
Netty的Reactor线程池是EventLoopGroup,而EventLoopGroup实际就是EventLoop的数组。EventLoop的职责是处理所有注册到本线程多路复用器Selector上的Channel。Selector的轮询操作是由其绑定的EventLoop线程run()方法驱动的,在一个循环体内循环执行。
三.设置并绑定服务端Channel
由于NIO服务端需要创建ServerSocketChannel,而Netty对NIO类库进行了封装,所以对应的就是NioServerSocketChannel。
Netty的ServerBootstrap方法提供了channel()方法用于指定服务端的Channel类型。Netty是通过工厂类(ServerBootstrap的父类AbstractBootstrap的ReflectiveChannelFactory实例),利用反射创建NioServerSocketChannel对象的。由于启动时才调用,所以该反射对运行时的性能没有影响。
四.创建并初始化ChannelPipeline
ChannelPipeline不是NIO服务端必需的,它本质是一个负责处理网络事件的职责链。ChannelPipeline这个职责链会负责管理和执行ChannelHandler。网络事件以事件流的形式在ChannelPipeline中流转,由ChannelPipeline根据ChannelHandler的执行策略来调度执行。
五.添加并设置ChannelHandler
ChannelHandler是Netty提供给用户定制和扩展的关键接口。利用ChannelHandler用户可以完成大多数的功能定制,如消息编解码、心跳、安全认证、流量控制和流量整形。
六.绑定并启动监听端口
在绑定监听端口之前,系统会做一系列的初始化和检测工作。完成之后便会启动监听端口,并将ServerSocketChannel注册到Selector上,然后监听客户端连接。
七.Selector轮询
由Reactor线程NioEventLoop负责调度和执行Selector轮询操作,选择准备就绪的Channel集合。
八.执行ChannelPipeline和ChannelHandler
当轮询到准备就绪的Channel之后,就由Reactor线程NioEventLoop执行ChannelPipeline的相应方法。即ChannelPipeline会根据网络事件的类型调度并执行ChannelHandler,最终执行Netty自带的ChannelHandler或用户定制的ChannelHandler。
典型的网络事件有:
一.channelRegistered() 链路注册
二.channelActive() 链路激活
三.channelInActive() 链路断开
四.channelRead() 接收到请求消息
五.channelReadComplete() 处理完请求消息
六.exceptionCaugh() 链路发生异常
常用的ChannelHandler有:
一.ByteToMessageCodec 消息编解码Handler
二.LoggingHandler 码流日志打印Handler
三.SslHandler SSL安全认证Handler
四.IdleStateHandler 链路空闲检测Handler
五.LengthFieldBasedFrameDecoder 基于长度域的半包解码Handler
六.ChannelTrafficShapingHandler 进行流量整形的Handler
七.Base64Decoder和Base64Encoder Base64编解码Handler
2.服务端启动的核心步骤
(1)由启动辅助类的外观接口实现启动
(2)启动辅助类的bind()方法
(3)启动辅助类的initAndRegister()方法
(4)服务端启动的4个核心步骤
(1)由启动辅助类的外观接口实现启动
用户给启动辅助类ServerBootstrap设置好参数后,会通过它的外观接口来实现启动。(2)启动辅助类的bind()方法
ServerBootstrap的bind()方法如下,来自其继承的抽象类AbstractBootstrap。- //Bootstrap sub-class which allows easy bootstrap of ServerChannel
- public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
- ...
- ...
- }
- //AbstractBootstrap is a helper class that makes it easy to bootstrap a Channel.
- //It support method-chaining to provide an easy way to configure the AbstractBootstrap.
- //When not used in a ServerBootstrap context, the #bind() methods are useful for connectionless transports such as datagram (UDP).
- public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
- ...
- //Create a new Channel and bind it.
- public ChannelFuture bind(int inetPort) {
- //首先根据端口号创建一个InetSocketAddress对象,然后调用重载方法bind()
- return bind(new InetSocketAddress(inetPort));
- }
-
- //Create a new Channel and bind it.
- public ChannelFuture bind(SocketAddress localAddress) {
- //验证服务启动需要的必要参数
- validate();
- if (localAddress == null) throw new NullPointerException("localAddress");
- return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
- }
-
- private ChannelFuture doBind(final SocketAddress localAddress) {
- final ChannelFuture regFuture = initAndRegister();//1.初始化和注册Channel
- final Channel channel = regFuture.channel();
- ...
- doBind0(regFuture, channel, localAddress, promise);//2.绑定服务端端口
- ...
- return promise;
- }
- ...
- }
复制代码 通过传入端口号调用AbstractBootstrap的bind()方法时,首先会根据端口号创建一个InetSocketAddress对象,然后继续调用重载方法bind()。重载方法bind()会先通过validate()方法验证服务启动需要的必要参数,然后调用doBind()方法。doBind()方法中的核心方法是:initAndRegister() + doBind0()。前者用于初始化和注册Channel,后者用于绑定服务端端口。
(3)启动辅助类的initAndRegister()方法- //AbstractBootstrap is a helper class that makes it easy to bootstrap a Channel.
- //It support method-chaining to provide an easy way to configure the AbstractBootstrap.
- public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
- ...
- final ChannelFuture initAndRegister() {
- Channel channel = null;
- ...
- //1.创建服务端Channel
- channel = channelFactory.newChannel();
- //2.初始化服务端Channel
- init(channel);
- ...
- //3.注册服务端Channel,比如通过NioEventLoopGroup的register()方法进行注册
- ChannelFuture regFuture = config().group().register(channel);
- ...
- return regFuture;
- }
- ...
- }
复制代码 (4)服务端启动的4个核心步骤
步骤一:创建服务端Channel
步骤二:初始化服务端Channel
步骤三:注册服务端Channel到Selector
步骤四:绑定服务端端口
3.创建服务端Channel的源码
(1)Channel的概念
(2)Channel的创建
(3)ChannelFactory的创建
(4)通过反射创建Channel对象
(5)创建JDK底层NIO的Channel
(6)创建Channel配置类
(7)设置Channel类型为非阻塞
(8创建Channel的核心组件
(9)创建服务端Channel总结
(1)Channel的概念
Netty官方对Channel的描述是:Channel可以理解为一个网络连接或者一个具有"读、写、连接、绑定"等IO操作能力的组件。Netty的Channel由于是在服务启动的时候创建的,可以和BIO中的ServerSocket对应,也和NIO中的ServerSocketChannel对应,所以符合上述IO组件的概念。
(2)Channel的创建
Channel是通过ChannelFactory的newChannel()方法创建出来的。
[code]//AbstractBootstrap is a helper class that makes it easy to bootstrap a Channel. //It support method-chaining to provide an easy way to configure the AbstractBootstrap.public abstract class AbstractBootstrap<B extends AbstractBootstrapB, C, C extends Channel> implements Cloneable { private volatile ChannelFactory |