Netty服务端源码流程分析
本节将简单分析下netty服务端的创建过程
1、服务端创建代码如下
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//创建服务器端的启动对象,配置参数
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
//给pipeline 设置处理器
@Override
protected void initChannel(SocketChannel ch) throws Exception {
System.out.println("客户socketchannel hashcode=" + ch.hashCode());
ch.pipeline().addLast(new NettyServerHandler());
}
});
System.out.println(".....服务器 is ready...");
//绑定一个端口并且同步, 生成了一个 ChannelFuture 对象
//启动服务器(并绑定端口)
ChannelFuture cf = bootstrap.bind(6668).sync();
//给cf 注册监听器,监控我们关心的事件
cf.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (cf.isSuccess()) {
System.out.println("监听端口 6668 成功");
} else {
System.out.println("监听端口 6668 失败");
}
}
});
//对关闭通道进行监听
cf.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
1.1、 创建NioEventLoopGroup
传入了一个默认的select策略工厂,INSTANCE信息如下图
继续调用构造方法
调用父类方法
由于我们没有设置系统属性变量io.netty.eventLoopThreads,所以DEFAULT_EVENT_LOOP_THREADS当前会取1,当前args可变数组中目前数据为
增加了DefaultEventExecutorChooserFactory
进入newChild方法
创建NioEventLoop对象,返回赋值给children数组
1.2、创建ServerBootstrap并配置参数
- 1.2.1、设置两个线程组
将bossGroup设置到父类的group属性
将workGroup设置到childGroup属性
- 1.2.2、使用NioSocketChannel 作为服务器的通道实现
创建ReflectiveChannelFactory对象并赋值给ServerBootstrap父类的channelFactory属性
- 1.2.3、设置线程队列得到连接个数
- 1.2.4、设置childHandler
1.3、绑定端口
进入initAndRegister,分为init和register两个部分
- init方法
图3↓
给当前channel的pipeline添加handler()
封装handler为DefaultChannelHandlerContext其父类为AbstractChannelHandlerContext,加入head和tail之间
将handler封装到PendingHandlerAddedTask对象中并将task对象赋值给pipeline的pendingHandlerCallbackHead属性
回到注册方法
- register
1、调用next方法选择一个线程
2、调用NioEventLoop的注册方法(SingkeThreadEventLoop是NioEventLoop的父类)
先将channel封装到DefaultChannelPromise中
图1↓****
启动线程前,添加任务到线程的队列中
启动线程,进入线程run方法
图4↓
接上图
调用hasTasks判断是否有任务
有任务就调用selectSupplier获取
此时结果返回0执行runAllTasks方法
拉取任务从队列中
任务是图1中的register0方法,回到图1位置
图2↓
注册主要就是将channel放入select中,并分配ops(个人理解,欢迎指正)
回到图2位置,调用invokeHandlerAddedIfNeeded
pendingHandlerCallbackHead是我们之前在init时放入的匿名对象(handler被封装成DefaultChannelHandlerContext继续封装到PendingHandlerAddedTask对象),见图3
调用task的execute方法,此时task就说封装了DefaultChannelHandlerContext的PendingHandlerAddedTask
调用initChannel,回到图3位置init代码流程
如果之前配置了handler,此时会将handler放入pipeline中,我们没有配置,只配置了childHandler,此时会创建ServerBootstrapAcceptor,放入pipeline中
private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
private final EventLoopGroup childGroup;
private final ChannelHandler childHandler;
private final Entry<ChannelOption<?>, Object>[] childOptions;
private final Entry<AttributeKey<?>, Object>[] childAttrs;
private final Runnable enableAutoReadTask;
ServerBootstrapAcceptor(
final Channel channel, EventLoopGroup childGroup, ChannelHandler childHandler,
Entry<ChannelOption<?>, Object>[] childOptions, Entry<AttributeKey<?>, Object>[] childAttrs) {
this.childGroup = childGroup;
this.childHandler = childHandler;
this.childOptions = childOptions;
this.childAttrs = childAttrs;
enableAutoReadTask = new Runnable() {
@Override
public void run() {
channel.config().setAutoRead(true);
}
};
}
@Override
@SuppressWarnings("unchecked")
public void channelRead(ChannelHandlerContext ctx, Object msg) {
final Channel child = (Channel) msg;
child.pipeline().addLast(childHandler);
setChannelOptions(child, childOptions, logger);
setAttributes(child, childAttrs);
try {
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}
}
...
回到图4,之前注册的操作是在runAllTasks中获取任务并执行的,继续图4的线程循环,获取任务不存在,
调用select 阻塞线程