当前位置: 首页 > news >正文

【图解IO与Netty系列】Netty核心组件解析

Netty核心组件解析

  • Bootstrap & ServerBootstrap
  • EventLoop & EventLoopGroup
  • Channel
  • ChannelHandler & ChannelPipeline & ChannelHandlerContext
    • ChannelHandler
    • ChannelPipeline
    • ChannelHandlerContext
  • ChannelFuture

Bootstrap & ServerBootstrap

Bootstrap和ServerBootstrap是Netty应用程序的启动引导器,通过它可以配置我们的Netty应用程序并启动。其中Bootstrap是Netty客户端使用的启动引导器,而ServerBootstrap则是Netty服务端使用的启动引导器。

EventLoop & EventLoopGroup

EventLoop是事件循环,也是就我们在NIO程序中while循环调用Selector的select()方法进行监听然后处理就绪事件的逻辑,现在Netty通过EventLoop封装事件循环,使得我们无需重复编写事件循环的代码,只需要专注于就绪事件的处理逻辑。

每个EventLoop都对应一个线程,每个EventLoop又属于某个EventLoopGroup,因此EventLoopGroup相当于是线程组。我们常用的是NioEventLoopGroup,NioEventLoopGroup内部包含了一个或多个NioEventLoop,由我们的参数进行设置。

在这里插入图片描述

一个NioEventLoop内部包含一个Selector和一个Queue<Runnable>类型的taskQueue。

在这里插入图片描述

Selector就是NIO中的Selector,Selector是一个多路复用器,我们可以往Selector注册多个Channel,Selector可以帮我们监听注册在其上的Channel,当我们调用Selector的select()方法时,当前线程就阻塞,通过Selector监听注册在其上的Channel,等待关注的事件就绪。

在这里插入图片描述

于是,NioEventLoop内部线程的事件循环,就通过Selector的select()方法监听注册到Selector上的Channel,等待一个或多个Channel有关注的事件就绪。

当有事件就绪时,NioEventLoop内部线程会调用processSelectedKeys()方法处理就绪事件对应的Channel。

当processSelectedKeys()方法调用完毕后,NioEventLoop还会调用runAllTasks()方法处理被提交到自己的taskQueue中的异步任务。一些比较耗时但是实时性不高的任务,我们可以把它提交到NioEventLoop的taskQueue中让它异步处理。

当taskQueue中的任务处理完,一个事件循环就结束,进入下一次循环。

在这里插入图片描述

Channel

这里的Channel和NIO的Channel不是同一个东西,这里的Channel是Netty对NIO的Channel经过封装后的属于Netty自己的Channel。比如NIO中的ServerSocketChannel和SocketChannel,Netty把它们封装成了NioServerSocketChannel和NioSocketChannel。

在这里插入图片描述

除了持有NIO的Channel以外,还保存了各自关注的事件类型,等真正把NIO的Channel注册到Selector上的时候,就可以直接设置对应的事件类型。NioServerSocketChannel保存的是连接就绪事件OP_ACCEPT,而NioSocketChannel保存的是读就绪事件OP_READ。

在这里插入图片描述

在使用Java原生的NIO时,我们都会设置Channel为非阻塞的,也就是调用configureBlocking(false)方法,这里Netty自动帮我们设置为非阻塞了,无需我们手动设置。比如NioServerSocketChannel在构造方法中就调用了ServerSocketChannel的configureBlocking(false)方法。

在这里插入图片描述

除了NioServerSocketChannel和NioSocketChannel以外,Netty还有其他类型的Channel,比如BIO类型的Channel、UDP协议的Channel,这里就不列举了。

然后Netty中的每个Channel,都有对应ChannelPipeline用来处理Channel中就绪的事件。

在这里插入图片描述

ChannelHandler & ChannelPipeline & ChannelHandlerContext

与Chandler相关的其他组件包括ChannelHandler、ChannelPipeline、ChannelHandlerContext。每个Chandler都会有一个ChandlerPipeline与之对应,用于处理该Chandler上发生的事件,而ChandlerPipeline又会通过它内部的ChandlerHandler去处理到来的事件。

ChannelHandler

ChannelHandler是专门用于处理就绪事件的,我们在开发Netty应用程序时,主要就是编写各种ChannelHandler,在ChannelHandler中各种事件触发的方法中实现自己的处理逻辑。

ChannelHandler又分为是处理入站事件还是出站事件的。所谓入站事件,就是由于接收到外部的数据或消息等而触发的事件就是入站事件,比如读就绪事件就是入站事件,因为有数据到达才会触发读就绪事件;而出站事件则与入站事件相反,由自己主动触发的,流动方向是向外的事件就是出站事件,比如写就绪事件。

在这里插入图片描述

如果要编写处理入站事件的ChannelHandler,我们可以实现ChannelInboundHandler接口,ChannelInboundHandler就是专门用于处理入站事件的;如果要编写处理出站事件的ChannelHandler,我们可以实现ChannelOutboundHandler接口,ChannelOutboundHandler就是专门用于处理出站事件的。

在这里插入图片描述

ChannelInboundHandler和ChannelOutboundHandler都继承了ChannelHandler接口。

在这里插入图片描述

但是ChannelInboundHandler和ChannelOutboundHandler有许多不同类型事件对应的方法,如果直接实现ChannelInboundHandler或ChannelOutboundHandler,我们要一一编写每个方法的实现逻辑。但是我们可能不会全部事件都关注,可能只会关注一两种类型的事件。

于是我们可以通过继承Netty提供的适配器类来实现我们的ChannelHandler,我们就可以选择性的实现我们关注的事件类型对应的方法。Netty提供的适配器类就是ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter,ChannelInboundHandlerAdapter是用于处理入站事件的适配器类,ChannelOutboundHandlerAdapter是用于处理出站事件的适配器类。

在这里插入图片描述

ChannelInboundHandlerAdapter实现了ChannelInboundHandler接口,而ChannelOutboundHandlerAdapter则实现了ChannelOutboundHandler接口。

在这里插入图片描述

ChannelPipeline

在Netty中,每个Channel对应一个ChannelPipeline。在Channel初始化的时候,就会为Channel创建一个对应的ChannelPipeline。ChannelPipeline是一个由多个ChannelHandler组成的双向链表,ChannelPipeline中有固定的head(头部Handler)和tail(尾部Handler)。

在这里插入图片描述

ChannelPipeline中除head和tail以外的ChannelHandler可以通过ChannelInitializer进行安装,一开始ChannelPipeline中除head和tail以外,中间只有一个ChannelInitializer。当Channel(NIO的Channel)被注册到Selector中时,会触发ChannelInitializer的调用,安装指定的ChannelHandler到Pipeline中,并把自己从链表中删除。

在这里插入图片描述

ChannelPipeline中对应就绪事件的处理,就是调用ChannelPipeline中的ChannelHandler与就绪事件匹配的方法。如果是入栈事件,则会以从head到tail的方向逐一调用负责处理入站事件的ChannelHandler来处理;如果是出站事件,则会以tail到head的方向逐一调用负责处理出站事件的ChannelHandler来处理。

在这里插入图片描述

ChannelHandlerContext

其实ChannelPipeline中的双向链表并不是由ChannelHandler直接组成的双向链表,而是在ChannelHandler外头再包了一层ChannelHandlerContext,因为ChannelHandler本身并没有维护组成双向链表需要的前后指针,ChannelHandlerContext才维护了这个前后指针,也就是说ChannelPipeline里头是由ChannelHandlerContext组成的双向链表。

在这里插入图片描述

之所以要在ChannelHandler之上再包一层ChannelHandlerContext来组成链表,是出于单一职责的考虑。首先ChannelHandler是用来处理事件的,那么ChannelHandler就应该只关注事件的处理,让它去维护前后指针就不太合适。就像LinkedList一样,我们放进去的元素,也不是直接组成双向链表的,LinkedList里头也是会包一个Node,再由Node的前后指针组成双向链表。

以下是ChannelHandlerContext的一些常用方法:
在这里插入图片描述

其中fireXxx是ChannelHandlerContext定义的以fire开头的一些方法,这些方法都是用于触发ChannelHandler中不同类型的事件处理方法,一旦调用这些方法,就会从当前ChannelHandlerContext开始沿着责任链调用每个ChannelHandler对应的事件的处理方法。比如调用了当前ChannelHandlerContext的fireChannelRead(Object msg)方法,就会从当前ChandlerHandlerContext对应的ChandlerHandler开始,沿着责任链顺序调用每个ChandlerHandler的channelRead(…)方法。

在这里插入图片描述

ChannelFuture

Netty中的操作都是异步操作,比如我们通过Bootstrap的connect(String inetHost, int inetPort)连接服务器、通过ServerBootstrap的bind(int inetPort)监听某个端口等,这些都是异步操作。这些异步操作都会返回一个ChannelFuture,我们可以通过ChannelFuture的addListener(…)方法添加一个ChannelFutureListener,等Netty的异步操作完成后,会触发添加到ChannelFuture的ChannelFutureListener进行相应的处理。

在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 地图元素。
  • MySQL快速入门(极简)
  • Buildroot和Debian文件系统修改方法
  • Java的IO流
  • VBA即用型代码手册:删除重复行Delete Duplicate Rows
  • 七天进阶elasticsearch[two]
  • 暴雨推出X705显示器:23.8英寸100Hz IPS屏
  • 重写setter方法要小心递归调用
  • [word] word悬挂缩进怎么设置? #经验分享#职场发展#经验分享
  • 25.逢七必过
  • Docker 学习总结(83)—— 配置文件daemon.json介绍及优化建议
  • python学习 - 在线 百度语音API 播报 测试案例分析
  • 二叉树最大宽度
  • 论文略读:Onthe Expressivity Role of LayerNorm in Transformers’ Attention
  • Spark MLlib机器学习
  • @jsonView过滤属性
  • 【翻译】babel对TC39装饰器草案的实现
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • angular组件开发
  • Codepen 每日精选(2018-3-25)
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • CSS魔法堂:Absolute Positioning就这个样
  • docker容器内的网络抓包
  • ES6系列(二)变量的解构赋值
  • express.js的介绍及使用
  • Flannel解读
  • Lsb图片隐写
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • 坑!为什么View.startAnimation不起作用?
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 在electron中实现跨域请求,无需更改服务器端设置
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • 阿里云ACE认证之理解CDN技术
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​Python 3 新特性:类型注解
  • #NOIP 2014# day.2 T2 寻找道路
  • #职场发展#其他
  • (06)金属布线——为半导体注入生命的连接
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (阿里云在线播放)基于SpringBoot+Vue前后端分离的在线教育平台项目
  • (附源码)ssm高校实验室 毕业设计 800008
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (利用IDEA+Maven)定制属于自己的jar包
  • (六)DockerCompose安装与配置
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (转)3D模板阴影原理
  • (转)c++ std::pair 与 std::make
  • (转)setTimeout 和 setInterval 的区别
  • .JPG图片,各种压缩率下的文件尺寸
  • .NET CLR Hosting 简介
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .Net 知识杂记
  • .Net转Java自学之路—SpringMVC框架篇六(异常处理)
  • .sh 的运行
  • @Tag和@Operation标签失效问题。SpringDoc 2.2.0(OpenApi 3)和Spring Boot 3.1.1集成