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

相关文章

检查 Nginx 是否启动的几种方法

《检查Nginx是否启动的几种方法》本文主要介绍了检查Nginx是否启动的几种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1. 使用 systemctl 命令(推荐)2. 使用 service 命令3. 检查进程是否存在4

MySQL中between and的基本用法、范围查询示例详解

《MySQL中betweenand的基本用法、范围查询示例详解》BETWEENAND操作符在MySQL中用于选择在两个值之间的数据,包括边界值,它支持数值和日期类型,示例展示了如何使用BETWEEN... 目录一、between and语法二、使用示例2.1、betwphpeen and数值查询2.2、be

解决idea启动项目报错java: OutOfMemoryError: insufficient memory

《解决idea启动项目报错java:OutOfMemoryError:insufficientmemory》:本文主要介绍解决idea启动项目报错java:OutOfMemoryError... 目录原因:解决:总结 原因:在Java中遇到OutOfMemoryError: insufficient me

SpringBoot项目整合Netty启动失败的常见错误总结

《SpringBoot项目整合Netty启动失败的常见错误总结》本文总结了SpringBoot集成Netty时常见的8类问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、端口冲突问题1. Tomcat与Netty端口冲突二、主线程被阻塞问题1. Netty启动阻

SpringBoot整合Kafka启动失败的常见错误问题总结(推荐)

《SpringBoot整合Kafka启动失败的常见错误问题总结(推荐)》本文总结了SpringBoot项目整合Kafka启动失败的常见错误,包括Kafka服务器连接问题、序列化配置错误、依赖配置问题、... 目录一、Kafka服务器连接问题1. Kafka服务器无法连接2. 开发环境与生产环境网络不通二、序

MySQL基本表查询操作汇总之单表查询+多表操作大全

《MySQL基本表查询操作汇总之单表查询+多表操作大全》本文全面介绍了MySQL单表查询与多表操作的关键技术,包括基本语法、高级查询、表别名使用、多表连接及子查询等,并提供了丰富的实例,感兴趣的朋友跟... 目录一、单表查询整合(一)通用模版展示(二)举例说明(三)注意事项(四)Mapper简单举例简单查询

Java JAR 启动内存参数配置指南(从基础设置到性能优化)

《JavaJAR启动内存参数配置指南(从基础设置到性能优化)》在启动Java可执行JAR文件时,合理配置JVM内存参数是保障应用稳定性和性能的关键,本文将系统讲解如何通过命令行参数、环境变量等方式... 目录一、核心内存参数详解1.1 堆内存配置1.2 元空间配置(MetASPace)1.3 线程栈配置1.

在DataGrip中操作MySQL完整流程步骤(从登录到数据查询)

《在DataGrip中操作MySQL完整流程步骤(从登录到数据查询)》DataGrip是JetBrains公司出品的一款现代化数据库管理工具,支持多种数据库系统,包括MySQL,:本文主要介绍在D... 目录前言一、登录 mysql 服务器1.1 打开 DataGrip 并添加数据源1.2 配置 MySQL

Nginx分布式部署流程分析

《Nginx分布式部署流程分析》文章介绍Nginx在分布式部署中的反向代理和负载均衡作用,用于分发请求、减轻服务器压力及解决session共享问题,涵盖配置方法、策略及Java项目应用,并提及分布式事... 目录分布式部署NginxJava中的代理代理分为正向代理和反向代理正向代理反向代理Nginx应用场景

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash