​前言

前面几篇博客主要介绍到了NIO针对网络IO场景相比较传统的Socket通信的优势,以及NIO在应用过程中线程模型的演化。从这篇博客开始我们一起来学习一个基于NIO实现的框架Netty,这是一个目前应用非常广泛的通信框架。Netty所使用的线程模型就是我们上一篇博客提到的主从Reactor模型。那么为什么在JDK中已经集成了NIO之后,还需要一个二次封装的Netty。这是因为NIO的使用门槛比较高,易用性比较低。具体可以参考我GIT上面NIO各种模式的Demo,可以看出实现一个通信模型的工作量还是比较大的,原生的NIO对用户来讲实现负担较重。Netty的出现就是为了帮助用户更多的专注在自己的业务逻辑上,降低实现成本。

介绍

我们结合一个简单的Demo来熟悉下Netty的主要API以及这些API背后的一些简单的架构设计理念。在这个过程中,我们会将Netty中的主要接口与之前的博客结合起来,看看Netty中的API是怎么与NIO的主从Reactor模式对应起来的。首先我们来一起看下一个Netty的Server端主要代码。

//主reactorEventLoopGroup acceptor = new NioEventLoopGroup();//从reactorEventLoopGroup worker =new NioEventLoopGroup();try {     ServerBootstrap bootstrap = new ServerBootstrap();     bootstrap.group(acceptor, worker);       bootstrap.option(ChannelOption.SO_BACKLOG, 1024);     bootstrap.channel(NioServerSocketChannel.class);     //主ractor处理器注册     bootstrap.handler(new LoggingHandler(LogLevel.INFO))               //从reactor处理器注册               .childHandler(newChannelInitializer<SocketChannel>() {                    @Override                    public void initChannel(SocketChannel ch) throws Exception {                        ch.pipeline().addLast(new DecodeHandler())                        .addLast(new ProcessHandler())                        .addLast(new DumpHandler());                    }                  });     ChannelFuture f = bootstrap.bind(port).sync();     f.channel().closeFuture().sync();} catch (InterruptedException e) {     e.printStackTrace();} finally {     acceptor.shutdownGracefully();     worker.shutdownGracefully();}

上面这段程序就是Netty Server的启动逻辑。基本的过程就是设置了一些Server的参数,设置事件监听对象,用户请求的处理逻辑等等。可以看到,整个实现过程很简洁,不需要关心任何关于NIO的细节。下面让我们一起来看下,每个接口都为我们做了哪些工作。

ServerBootstrap

ServerBootstrap从字面翻译过来是服务器引导程序的意思。这个类是Server端的主要类,可以看到关于服务端的所有配置和逻辑都是通过该类进行设置或者注册的。可以认为所有服务端的实现和配置都被包裹在ServerBootstrap之内。我们开发服务端代码的主要目的就是构建该对象,利用接口去配置相关的参数,向其中去注册我们的处理逻辑,最后启动ServerBootstrap即可。

EventLoopGroup

EventLoopGroup与我们前面博客中提到的Reactor是相对应的,一个EventLoopGroup就是对应着一个Reactor对象。从Demo中可以看到定义了两个group对象,acceptor和worker。这两个group分别对应着我们的主从reactor。回顾下我们上一篇博客中的内容,不难想到,这两个group都包含了可以独立运行的线程,每个group中都封装了NIO的Selector对象并运行独立的事件监听线程。其中acceptor负责客户端的连接请求事件,worker负责数据读取和发送事件。事实上也确实如此,EventLoopGroup的类继承关系如下:

(该图像摘自:https://www.cnblogs.com/duanxz/p/3724395.html)

从继承关系上可以看出每个group都是一个独立的线程池实现(该类的实现细节,后续在Netty源码分析的系列博客中还会进行详细介绍)。此处我们希望联系前面博客中的主从Reactor模型的验证Netty的实现与前期的理解是一致的。

ChannelHandler

有了事件分发器,接下来就是具体的事件处理逻辑。事件的处理逻辑跟我们的业务密切相关,每个业务都有其独特性,显然这部分逻辑不可能由框架来实现。框架需要做的就是提供给用户自定义的口子。这个口子就是ChannelHandler。ChannelHandler是框架提供的一个处理器基类,它定义了Event处理的接口标准,用户通过override相应的接口来实现自己的处理逻辑。这也是大部分框架进行业务逻辑解耦的一种惯用方式。用户自定义实现了Handler之后只需要将自己的Handler对象注册到Bootstrap中即可。

值得注意的是,我们的框架分为了主从Reactor来对不同的事件进行分发处理,自然Handler的注册也分为了两类。因此在Demo代码中可以看出,Handler的注册也是分两个不同的接口进行注册的。Handler接口注册的主Reactor的处理器,即负责处理accept事件,childHandler接口注册的是从Reactor的处理器,即负责处理read,write事件。

Pipeline的设计理念

通过上面几个核心API的串联,我们基本上完成了整个服务端的处理过程梳理。从服务端参数的配置,事件的监听分发和用户自定义处理器的添加,这些基本上是一个完整的通信程序的所有要素。那么为什么还要设计一个Pipeline那。

回答是功能复用和逻辑解耦。Pipeline的字面意思是管道,我更喜欢翻译成流水线。流水线是一种生产作业方式,我们所有的生产处理过程都可以通过组合不同的基础处理能力,以流水作业的方式来实施。而我们这里的Pipeline起到的作用就是这个。我们每个业务的处理逻辑都是以流水线的方式,串联一组handler组合形成的。框架为我们定义和实现了不同handler之间进行数据传输和流转的的标准。这种方式方便业务逻辑进行灵活的逻辑扩展,不需要把所有的逻辑堆砌在某一个handler中。具体来说好处有以下两点。

第一个好处是功能复用,虽然说每个业务的处理逻辑都是不一样的,有其独特的地方。但是差异中也是能发掘到共同点的,这些共同点就可以作为公用的Handler沉淀下来,其他业务在开发时就可以拿来即用(串接到Pipeline中)。甚至有些能够形成业界统一标准的通用处理逻辑可以集成到Netty框架中供所有人使用,这就所谓的功能复用。

第二个好处是逻辑解耦。在架构整洁之道一书中提到,架构设计本身就是一门划分边界的艺术。是的,我们常常称一个低耦合的软件架构为优秀的设计,而解耦的前提就是进行边界划分。将软件架构中不容易变化的部分和容易变化的部分的边界分析出来,然后再通过一个通用的轻量的标准纽带联系起来就能完成解耦。通过Pipeline用户就能够轻松的进行这种边界切割和逻辑解耦。当然,如果没有Pipeline,用户也能够自行实现一个解耦业务逻辑。但是在Pipeline的基础上,这种实现能够做到事半功倍。更重要的是这种实现模式向更多的人推广了边界划分的设计理念,增强了他们主动进行功能单元划分的意识。甚至还会长远的影响到一部分人的软件设计理念。

Netty客户端的实现这里就不介绍了,基本上跟服务端的套路差不多。

后话

搭建一个简单的Netty应用并不难,网络上也大量的Demo程序可以参考。但是我写这一篇博客的初衷更多的还是希望能够将Netty中的API与我们前面博客中提到的NIO的概念和线程模型对应起来,从而形成上下连贯。

另外Pipeline这种插件式架构的设计理念也是值得我们在自行设计的软件中去落地实践的。最后向大家推荐一本上面提到的书:架构整洁之道。

一起来分解一个Netty应用相关推荐

  1. 《Netty In Action》第二章:第一个Netty程序

    2019独角兽企业重金招聘Python工程师标准>>> 源码地址: GitHub 2.3 编写一个应答服务器 写一个Netty服务器主要由两部分组成: 配置服务器功能,如线程.端口 ...

  2. 第一个Netty应用

    本文来做一个Netty的入门程序,即Netty的hello word入门级程序 文章目录 概述 导入Netty依赖 服务端 创建服务端 自定义服务端 ChannelHandler 处理消息 客户端 创 ...

  3. 1、张龙netty学习 第一个netty服务端

    张龙netty学习 第一个netty服务端 public class TestServer {public static void main(String[] args) throws Excepti ...

  4. C语言:求分解一个任意合数为质数乘积形式

    C语言:求分解一个任意合数为质数乘积形式 如: 100是要分成2*2*5*5才算最后的答案 7=1*7的形式是正确的 16=2*2*2*2 正确 #include<stdio.h> mai ...

  5. Netty介绍 与第一个Netty实例

    官网:https://netty.io/ 以下内容大部分来自Netty官网内容 一.现有问题 现在我们使用通用应用程序或库来彼此通信.例如,我们经常使用HTTP客户端库从web服务器检索信息,并通过w ...

  6. WebSocket不同版本的三种握手方式以及一个Netty实现JAVA类

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 一.We ...

  7. Netty网络编程实战1,搭建第一个Netty服务器

    目录 一.Netty是什么 二.Hello Netty 1.主程序类MyNettyServerTest 2.初始化器MyNettyServerInitializer 3.自定义处理器MyNettySe ...

  8. 教你用 Netty 实现一个简单的 RPC!

    众所周知,dubbo 底层使用了 Netty 作为网络通讯框架,而 Netty 的高性能我们之前也分析过源码,对他也算还是比较了解了. 今天我们就自己用 Netty 实现一个简单的 RPC 框架. 1 ...

  9. Netty之实现一个简单的群聊系统

    要求 编写一个 Netty 群聊系统,实现服务器端和客户端之间的数据简单通讯(非阻塞) 实现多人群聊 服务器端:可以监测用户上线,离线,并实现消息转发功能 客户端:通过channel可以无阻塞发送消息 ...

最新文章

  1. 三维重建缺数据集?来看看Facebook最新发布的CO3D
  2. linux 编辑文件删除不了怎么办,Linux中文件/文件夹无法删除的解决方案
  3. maven web工程用MyEclipse Deploy后tomcat下无文件
  4. 深度 | 容器规模化落地企业的最佳途径
  5. OpenCV重新映射Remap的实例(附完整代码)
  6. 分享实录|争议不断地EOS,我们如何才能理性看待?
  7. Ollydbg使用教程学习总结(四)
  8. 面试官 | 为什么用了索引之后,查询就会变快?
  9. Java之读写锁ReadWriteLock实现
  10. 正则表达式re中的group和groups
  11. Tableau详细安装教程【踩坑】
  12. 45个免费LOGO在线制作网站
  13. 短信验证码平台必须具备特点有哪些?
  14. 3DMax一个重要功能,通过它制作出来的影视作品有很强立体感
  15. 图像恢复系列之(6)超分(7)反光去除(8)光斑去除 (9)阴影去除(10)水下图像失真去除 | ICCV2021生成对抗GAN...
  16. React TypeScript 从零实现 Popup 组件发布到 npm
  17. 安装rouge和pyrouge
  18. spring成神之路第三十八篇:@Scheduled @EnableScheduling 定时器详解
  19. 杭州银行客服中心的智能化转型之路
  20. egg项目服务器部署,egg部署到服务器

热门文章

  1. 微服务看门神-Zuul
  2. 工业机器人三点工具定位法图文_手把手教你工业机器人三点示教法
  3. matlab双目相机标定校正_双目相机的标定过程详解!-----MATLAB
  4. 【CQBZ模拟赛】星际旅行
  5. 速卖通装修html自定义代码,Shopify基础建站教程,独立站装修主题代码设置
  6. 用C#与数据库实现吃货联盟订餐系统
  7. J2EE中相对路径和绝对路径
  8. 压力测试工具之FIO
  9. android 11.0 12.0自定义开机向导app
  10. 一文了解蛋白功能结构域预测与分析