Netty服务端基本启动流程源码刨析

2024-03-28 00:04

本文主要是介绍Netty服务端基本启动流程源码刨析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言: 希望看这篇文章之前对Java Nio编程比较熟悉,并有用过Netty开发简单代码

服务端代码

先大致说一下NioEventLoopGroup组件的作用,可以把它看是作内部维护了一个NioEventLoop数组的对象,它的构造方法的参数用来指定维护数组的大小。NioEventLoop继承自Executor可以理解为一个NioEventLoop是一个单线程线程池。

ServerBootStrap作为一个封装Java Nio 的一个启动类接下来我们分析这个启动类

首先bootstrap.group(boss,eventExecutors)这段代码内部为SerBootStrap属性赋值,分别赋值给Group和childGroup。Group即boss线程组主要负责通过Java Nio建立连接 ,childGroup主要负责监听Group传递过来的Channel。

channel方法内部是根据类对象创建一个channelFactory工厂,用来通过反射创建NioServerSocketChannel,这里的Channel完全是Netty自己的类不是JavaNio自带的类

重点在bind方法内部

内部调用doBind方法,接下来注意initAndRegister方法

通过工厂方法创建channel,由于NioServerSocketChannel继承了AbstractChannel,先看父类构造方法都做了什么

unsafe类不是Java中的操作内存的Unsafe类,这里的unsafe类是用来读取和写入消息进行的封装,pipeline可以理解为是一个链表,每个节点是ChannelHandler和上下文信息封装而成

NioServerSockerChannel构造方法内还创建了Java Nio的ServerSocketChannel

这里代码图片就不粘贴了可以自己动手看,其内部就是把ServerSocketChannel赋值给NioServerSocketChannel的一个属性,如果后续代码中NioServerSocketChannel调用javaChannel()方法返回的就是这个属性即Java原生ServerSocketChannel。

Config内部等于保存了NioServerSocketChannel的引用,以及初始化了ByteBuf内存分配器

至此 channelFactory创建channel的方法结束

此时NioServerSocketChannel内部只是保留了对ServerSocketChannel的引用,并未对ServerSocketChannel注册事件等等

接下来注意Init方法

可以看到它主要做了一些参数信息的设置以及添加了一个HandlerContext,这里等于说是一个头节点和一个这个节点以及一个尾节点构成pipleline。这里留意一下execute方法,参数currentChildGroup就是开头的NioEventLoopGroup(child),这里的currentChildHandler是我们最开始片段的Handler,以及Options都是最开始专门为ChildHandler设置的

这里Init方法结束,接下来看initAndRegister方法中的Register方法

这里的config是上一步的config对象,这里的group是最开始创建的Boss线程组 NioEventLoopGroup,进入register方法内部

 public ChannelFuture register(Channel channel) {return next().register(channel);}

next()方法主要是从线程组中挑出一个NioEventLoop即只有一个线程的线程池,再次深入register方法

我们发现这里的promise封装了NioServerSocketChannel和从Group中挑出的线程池

接下来是重中之重涉及到线程的开启和切换

Unsafe的register方法

这里的inEventLoop其实是判断当前线程是否是NioEventLoop中的线程,NioEventLoop中的线程采用懒惰加载,第一次为null所以判断结果为false。

我们可以看到他向单线程线程池(NioEventLoop)任务队列中提交了一个普通任务

接着调用startThread方法,直接看其内部的doStartThread方法

看左下角当前线程是NioEventLoopGroup中的一个线程,并把此线程赋值给Thread属性(懒加载),接着进入SingleThreadEventExecutor.this.run()方法,这里的this.run指的是NioEventLoop的run方法

这里我要引入一张图片来解释run方法的功能

我们现在只处在BossGroup中,注意下面的圆圈这里就是这段代码的功能我们一句一句看

这里的selectStrategy.calculateStrategy(selectNowSupplier, hasTasks());方法是判断普通任务队列(非定时任务)是否有待完成的任务,这里显然是有的上面已经说了提交了一个任务register0,但是这里面的作用是如果有任务就调用selectNow方法,看返回的是否有事件发生。

因为NioEventLoop毕竟是线程池除了要监听channel事件还要处理普通任务和定时任务

如果没有普通任务返回的就是枚举类SELECT

long curDeadlineNanos = nextScheduledTaskDeadlineNanos();计算的是定时任务的最小时间,这里是为了下面调用Select.select(time)有限时间监听channel事件。正如之前所说:NioEventLoop毕竟是线程池除了要监听channel事件还要处理普通任务和定时任务

上面主要是解决定时任务的情况方法就是有限时间的等待,由于我们只提交了register0任务继续向下看,看它是如何处理普通任务和channel中发生事件的

这段代码要留意selectCnt++,ioRatio,processSelectedKeys(),ranTasks = runAllTasks(ioTime * (100 - ioRatio) / ioRatio)

首先 processSelectedKeys()是为了处理Channel中有注册事件发生,我们代码中目前还没有连接事件

所以就看runAllTask方法

其内部就是从队列中拿到之前提交的task任务

看!该执行我们之前提交的任务了

看此方法内部 doRegister方法

这里任务的提交以及register方法都是在NioServerSocketChannel的父类中完成

selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);

这段代码就是把Netty中的NioServerSocketChannel当作附件给添加到Java Nio中ServerSocketChannel,并把它注册到selector中

同时调用HandlerContext的initChannel方法,把任务提交向pipleLine中添加一个HandlerContext

到这里启动流程基本就这些,事件的处理selectCnt++,ioRatio,processSelectedKeys(),下篇文章继续

这篇关于Netty服务端基本启动流程源码刨析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/853845

相关文章

Spring Security中用户名和密码的验证完整流程

《SpringSecurity中用户名和密码的验证完整流程》本文给大家介绍SpringSecurity中用户名和密码的验证完整流程,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定... 首先创建了一个UsernamePasswordAuthenticationTChina编程oken对象,这是S

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

SQL BETWEEN 语句的基本用法详解

《SQLBETWEEN语句的基本用法详解》SQLBETWEEN语句是一个用于在SQL查询中指定查询条件的重要工具,它允许用户指定一个范围,用于筛选符合特定条件的记录,本文将详细介绍BETWEEN语... 目录概述BETWEEN 语句的基本用法BETWEEN 语句的示例示例 1:查询年龄在 20 到 30 岁

nginx启动命令和默认配置文件的使用

《nginx启动命令和默认配置文件的使用》:本文主要介绍nginx启动命令和默认配置文件的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录常见命令nginx.conf配置文件location匹配规则图片服务器总结常见命令# 默认配置文件启动./nginx

mysql中insert into的基本用法和一些示例

《mysql中insertinto的基本用法和一些示例》INSERTINTO用于向MySQL表插入新行,支持单行/多行及部分列插入,下面给大家介绍mysql中insertinto的基本用法和一些示例... 目录基本语法插入单行数据插入多行数据插入部分列的数据插入默认值注意事项在mysql中,INSERT I

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

mapstruct中的@Mapper注解的基本用法

《mapstruct中的@Mapper注解的基本用法》在MapStruct中,@Mapper注解是核心注解之一,用于标记一个接口或抽象类为MapStruct的映射器(Mapper),本文给大家介绍ma... 目录1. 基本用法2. 常用属性3. 高级用法4. 注意事项5. 总结6. 编译异常处理在MapSt

Nexus安装和启动的实现教程

《Nexus安装和启动的实现教程》:本文主要介绍Nexus安装和启动的实现教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Nexus下载二、Nexus安装和启动三、关闭Nexus总结一、Nexus下载官方下载链接:DownloadWindows系统根