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

相关文章

通过Docker容器部署Python环境的全流程

《通过Docker容器部署Python环境的全流程》在现代化开发流程中,Docker因其轻量化、环境隔离和跨平台一致性的特性,已成为部署Python应用的标准工具,本文将详细演示如何通过Docker容... 目录引言一、docker与python的协同优势二、核心步骤详解三、进阶配置技巧四、生产环境最佳实践

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

redis-sentinel基础概念及部署流程

《redis-sentinel基础概念及部署流程》RedisSentinel是Redis的高可用解决方案,通过监控主从节点、自动故障转移、通知机制及配置提供,实现集群故障恢复与服务持续可用,核心组件包... 目录一. 引言二. 核心功能三. 核心组件四. 故障转移流程五. 服务部署六. sentinel部署

Python ORM神器之SQLAlchemy基本使用完全指南

《PythonORM神器之SQLAlchemy基本使用完全指南》SQLAlchemy是Python主流ORM框架,通过对象化方式简化数据库操作,支持多数据库,提供引擎、会话、模型等核心组件,实现事务... 目录一、什么是SQLAlchemy?二、安装SQLAlchemy三、核心概念1. Engine(引擎)

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

SpringBoot通过main方法启动web项目实践

《SpringBoot通过main方法启动web项目实践》SpringBoot通过SpringApplication.run()启动Web项目,自动推断应用类型,加载初始化器与监听器,配置Spring... 目录1. 启动入口:SpringApplication.run()2. SpringApplicat

Python异步编程之await与asyncio基本用法详解

《Python异步编程之await与asyncio基本用法详解》在Python中,await和asyncio是异步编程的核心工具,用于高效处理I/O密集型任务(如网络请求、文件读写、数据库操作等),接... 目录一、核心概念二、使用场景三、基本用法1. 定义协程2. 运行协程3. 并发执行多个任务四、关键

解决Nginx启动报错Job for nginx.service failed because the control process exited with error code问题

《解决Nginx启动报错Jobfornginx.servicefailedbecausethecontrolprocessexitedwitherrorcode问题》Nginx启... 目录一、报错如下二、解决原因三、解决方式总结一、报错如下Job for nginx.service failed bec

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

MySQL 临时表与复制表操作全流程案例

《MySQL临时表与复制表操作全流程案例》本文介绍MySQL临时表与复制表的区别与使用,涵盖生命周期、存储机制、操作限制、创建方法及常见问题,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小... 目录一、mysql 临时表(一)核心特性拓展(二)操作全流程案例1. 复杂查询中的临时表应用2. 临时