五 Netty 学习:服务端启动核心流程源码说明

Netty 学习(五):服务端启动核心流程源码说明作者: Grey
原文地址:
博客园:Netty 学习(五):服务端启动核心流程源码说明
CSDN:Netty 学习(五):服务端启动核心流程源码说明
说明本文使用的 Netty 版本是 4.1.82.Final,
<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.82.Final</version></dependency>服务端在启动的时候,主要流程有如下几个

  1. 创建服务端的 Channel
  2. 初始化服务端的 Channel
  3. 注册 Selector
  4. 端口绑定
我们可以写一个简单的服务端代码,通过 Debug 的方式查看这几个关键流程的核心代码 。
package source;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;import io.netty.channel.ChannelInitializer;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;/** * 代码阅读 * * @author <a href="mailto:410486047@qq.com">Grey</a> * @date 2022/9/12 * @since */public final class SimpleServer {public static void main(String[] args) throws InterruptedException {// EventLoopGroup: 服务端的线程模型外观类 。这个线程要做的事情// 就是不停地检测IO事件,处理IO事件,执行任务 。EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {// 服务端的一个启动辅助类 。通过给它设置一系列参数来绑定端口启动服务 。ServerBootstrap b = new ServerBootstrap();b// 设置服务端的线程模型 。// bossGroup 负责不断接收新的连接 , 将新的连接交给 workerGroup 来处理 。.group(bossGroup, workerGroup)// 设置服务端的 IO 类型是 NIO 。Netty 通过指定 Channel 的类型来指定 IO 类型 。.channel(NioServerSocketChannel.class)// 服务端启动过程中,需要经过哪些流程 。.handler(new ChannelInboundHandlerAdapter() {@Overridepublic void channelActive(ChannelHandlerContext ctx) {System.out.println("channelActive");}@Overridepublic void channelRegistered(ChannelHandlerContext ctx) {System.out.println("channelRegistered");}@Overridepublic void handlerAdded(ChannelHandlerContext ctx) {System.out.println("handlerAdded");}})// 用于设置一系列 Handler 来处理每个连接的数据.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel socketChannel) {}});// 绑定端口同步等待 。等服务端启动完毕 , 才会进入下一行代码ChannelFuture f = b.bind(8888).sync();// 等待服务端关闭端口绑定 , 这里的作用是让程序不会退出f.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}}通过
ChannelFuture f = b.bind(8888).sync();bind方法 , 进入源码进行查看 。
首先 , 进入的是AbstractBootstrap中 , 调用的最关键的方法是如下两个:
……private ChannelFuture doBind(final SocketAddress localAddress) {……final ChannelFuture regFuture = initAndRegister();……doBind0(regFuture, channel, localAddress, promise);……}……进入initAndResgister()方法中
……final ChannelFuture initAndRegister() {……// channel 的新建channel = channelFactory.newChannel();// channel 的初始化init(channel);……}……这里完成了 Channel 的新建和初始化 , Debug 进去,发现channelFactory.newChannel()实际上是调用了ReflectiveChannelFactorynewChannel方法,
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {……private final Constructor<? extends T> constructor;public ReflectiveChannelFactory(Class<? extends T> clazz) {……this.constructor = clazz.getConstructor();……}@Overridepublic T newChannel() {……return constructor.newInstance();……}……}这里调用了反射方法,其实就是将服务端代码中的这一行.channel(NioServerSocketChannel.class)中的NioServerSocketChannel.class传入进行对象创建,创建一个NioServerSocketChannel实例 。
在创建NioServerSocketChannel的时候,调用了NioServerSocketChannel的构造方法,构造方法的主要逻辑如下
……public NioServerSocketChannel(SelectorProvider provider, InternetProtocolFamily family) {this(newChannel(provider, family));}public NioServerSocketChannel(ServerSocketChannel channel) {super(null, channel, SelectionKey.OP_ACCEPT);config = new NioServerSocketChannelConfig(this, javaChannel().socket());}private static ServerSocketChannel newChannel(SelectorProvider provider, InternetProtocolFamily family) {……ServerSocketChannel channel =SelectorProviderUtil.newChannel(OPEN_SERVER_SOCKET_CHANNEL_WITH_FAMILY, provider, family);return channel == null ? provider.openServerSocketChannel() : channel;……}……

推荐阅读