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

企业网站的设计论文wordpress资源消耗

企业网站的设计论文,wordpress资源消耗,公司网站建设制度,简阳seo排名优化培训文章目录 概述整体结构Netty的核心组件逻辑架构BootStrap ServerBootStrapChannelPipelineFuture、回调和 ChannelHandler选择器、事件和 EventLoopChannelHandler的各种ChannelInitializer类图 Protocol Support 协议支持层Transport Service 传输服务层Core 核心层模块… 文章目录 概述整体结构Netty的核心组件逻辑架构BootStrap ServerBootStrapChannelPipelineFuture、回调和 ChannelHandler选择器、事件和 EventLoopChannelHandler的各种ChannelInitializer类图 Protocol Support 协议支持层Transport Service 传输服务层Core 核心层模块netty-common模块netty-buffer 模块netty-codec模块 Netty是如何处理连接请求和业务逻辑的呢 -- Channels、Events 和 IO 我们看看Netty是如何处理数据的-- Netty核心ChannelHandlerNetty中Pipeline工作原理 概述 Netty 是由 JBOSS 提供的一个 Java 开源框架。Netty 提供异步的、基于事件驱动的网络应用程序框架用以快速开发高性能、高可靠性的网络 IO 程序。Netty 主要用来做网络通信一般可以用来作RPC框架的通信工具、实现即时通讯系统以及实时消息推送系统等。 Netty是一个异步事件驱动的网络应用程序框架用于快速开发可维护的高性能协议服务器和客户端。Netty是一个NIO客户端服务器框架可以快速轻松地开发协议服务器和客户端等网络应用程序。 它极大地简化并简化了TCP和UDP套接字服务器等网络编程。 学习任何一门技术都需要有全局观在开始上手的时候不宜陷入琐碎的技术细节避免走进死胡同。以 Netty 4.1.42 为基准版本 整体结构 Netty 是一个设计非常用心的网络基础组件Netty 官网给出了有关 Netty 的整体功能模块结构却没有其他更多的解释。 Core 核心层 Core 核心层是 Netty 最精华的内容它提供了底层网络通信的通用抽象和实现 可扩展的事件模型 通用的通信 API 支持零拷贝的 ByteBuf 以上便是 Netty 的逻辑处理架构可以看出 Netty 的架构分层设计得非常合理屏蔽了底层 NIO 以及框架层的实现细节对于业务开发者来说只需要关注业务逻辑的编排和实现即可。 Netty的核心组件 Netty的核心组件分为三层分别是网络通信层、事件调度层和服务编排层。 简单讲netty是一个基于协议支持快速构建客户端、服务端用于网络io交互的异步非阻塞、高性能、可维护框架。 为了更好的理解和进一步深入Netty我们先总体认识一下Netty用到的组件及它们在整个Netty架构中是怎么协调工作的。Netty应用中必不可少的组件 ● Bootstrap or ServerBootstrap ● EventLoop ● EventLoopGroup ● ChannelPipeline ● Channel ● Future or ChannelFuture ● ChannelInitializer ● ChannelHandler Bootstrap一个Netty应用通常由一个Bootstrap开始它主要作用是配置整个Netty程序串联起各个组件。 Handler为了支持各种协议和处理数据的方式便诞生了Handler组件。Handler主要用来处理各种事件这里的事件很广泛比如可以是连接、数据接收、异常、数据转换等。 ChannelInboundHandler一个最常用的Handler。这个Handler的作用就是处理接收到数据时的事件也就是说我们的业务逻辑一般就是写在这个Handler里面的ChannelInboundHandler就是用来处理我们的核心业务逻辑。 ChannelInitializer当一个链接建立时我们需要知道怎么来接收或者发送数据当然我们有各种各样的Handler实现来处理它那么ChannelInitializer便是用来配置这些Handler它会提供一个ChannelPipeline并把Handler加入到ChannelPipeline。 ChannelPipeline一个Netty应用基于ChannelPipeline机制这种机制需要依赖于EventLoop和EventLoopGroup因为它们三个都和事件或者事件处理相关。 EventLoops的目的是为Channel处理IO操作一个EventLoop可以为多个Channel服务。 EventLoopGroup会包含多个EventLoop。 Channel代表了一个Socket链接或者其它和IO操作相关的组件它和EventLoop一起用来参与IO处理。 Future在Netty中所有的IO操作都是异步的因此你不能立刻得知消息是否被正确处理但是我们可以过一会等它执行完成或者直接注册一个监听具体的实现就是通过Future和ChannelFutures,他们可以注册一个监听当操作执行成功或失败时监听会自动触发。总之所有的操作都会返回一个ChannelFuture。 逻辑架构 Netty 的逻辑处理架构为典型网络分层架构设计共分为网络通信层、事件调度层、服务编排层每一层各司其职。 网络通信层 网络通信层的职责是执行网络 I/O 的操作。它支持多种网络协议和 I/O 模型的连接操作。当网络数据读取到内核缓冲区后会触发各种网络事件这些网络事件会分发给事件调度层进行处理。 网络通信层的核心组件包含BootStrap、ServerBootStrap、Channel三个组件。 BootStrap ServerBootStrap BootStrap 和 ServerBootStrap 分别负责客户端和服务端的启动它们是非常强大的辅助工具类 ● Bootstrap 是“引导”的意思它主要负责整个 Netty 程序的启动、初始化、服务器连接等过程它相当于一条主线串联了 Netty 的其他核心组件。 如下图所示Netty 中的引导器共分为两种类型 ○ 一个为用于客户端引导的 Bootstrap ○ 一个为用于服务端引导的 ServerBootStrap 它们都继承自抽象类 AbstractBootstrap。 区别 Bootstrap 和 ServerBootStrap 十分相似两者非常重要的区别在于 ● Bootstrap 可用于连接远端服务器只绑定一个 EventLoopGroup。 ● ServerBootStrap 则用于服务端启动绑定本地端口会绑定两个 EventLoopGroup这两个 EventLoopGroup 通常称为 Boss 和 Worker。 ○ 这里的 Boss 和 Worker 可以理解为“老板”和“员工”的关系。 ○ 每个服务器中都会有一个 Boss也会有一群做事情的 Worker。 ○ Boss 会不停地接收新的连接然后将连接分配给一个个 Worker 处理连接。 有了 Bootstrap 组件我们可以更加方便地配置和启动 Netty 应用程序它是整个 Netty 的入口串接了 Netty 所有核心组件的初始化工作。 Channel Channel 是网络通信的载体提供了与底层 Socket 交互的能力。 Channel 生命周期内的事件都是如何被处理的呢那就是 Netty 事件调度层的工作职责了。 Channel 的字面意思是“通道”它是网络通信的载体。Channel提供了基本的 API 用于网络 I/O 操作如 register、bind、connect、read、write、flush 等。 Netty 自己实现的 Channel 是以 JDK NIO Channel 为基础的相比较于 JDK NIONetty 的 Channel 提供了更高层次的抽象同时屏蔽了底层 Socket 的复杂性赋予了 Channel 更加强大的功能你在使用 Netty 时基本不需要再与 Java Socket 类直接打交道。 家族图谱 ● AbstractChannel 是整个家族的基类 ● 派生出 AbstractNioChannel、AbstractOioChannel、AbstractEpollChannel 等子类每一种都代表了不同的 I/O 模型和协议类型 常用的 Channel 实现类有 ● NioServerSocketChannel 异步 TCP 服务端。 ● NioSocketChannel 异步 TCP 客户端。 ● OioServerSocketChannel 同步 TCP 服务端。 ● OioSocketChannel 同步 TCP 客户端。 ● NioDatagramChannel 异步 UDP 连接。 ● OioDatagramChannel 同步 UDP 连接。 当然 Channel 会有多种状态如连接建立、连接注册、数据读写、连接销毁等。随着状态的变化Channel 处于不同的生命周期每一种状态都会绑定相应的事件回调。 事件调度层 事件调度层的职责是通过 Reactor 线程模型对各类事件进行聚合处理通过 Selector 主循环线程集成多种事件 I/O 事件、信号事件、定时事件等实际的业务处理逻辑是交由服务编排层中相关的 Handler 完成。 事件调度层的核心组件包括 EventLoopGroup、EventLoop。 EventLoopGroup EventLoop EventLoopGroup 本质是一个线程池主要负责接收 I/O 请求并分配线程执行处理请求。 几点关系 一个 EventLoopGroup 往往包含一个或者多个 EventLoop。 EventLoop 用于处理 Channel 生命周期内的所有 I/O 事件如 accept、connect、read、write 等 I/O 事件。 EventLoop 同一时间会与一个线程绑定每个 EventLoop 负责处理多个 Channel。 每新建一个 ChannelEventLoopGroup 会选择一个 EventLoop 与其绑定。该 Channel 在生命周期内都可以对 EventLoop 进行多次绑定和解绑。 家族图谱 可以看出 Netty 提供了 EventLoopGroup 的多种实现而且 EventLoop 则是 EventLoopGroup 的子接口所以也可以把 EventLoop 理解为 EventLoopGroup但是它只包含一个 EventLoop 。 EventLoopGroup 的实现类是 NioEventLoopGroupNioEventLoopGroup 也是 Netty 中最被推荐使用的线程模型。NioEventLoopGroup 继承于 MultithreadEventLoopGroup是基于 NIO 模型开发的可以把 NioEventLoopGroup 理解为一个线程池每个线程负责处理多个 Channel而同一个 Channel 只会对应一个线程。 线程模型 EventLoopGroup 是 Netty 的核心处理引擎 那么 EventLoopGroup 和之前课程所提到的 Reactor 线程模型到底是什么关系呢 其实 EventLoopGroup 是 Netty Reactor 线程模型的具体实现方式Netty 通过创建不同的 EventLoopGroup 参数配置就可以支持 Reactor 的三种线程模型 undefined 单线程模型EventLoopGroup 只包含一个 EventLoopBoss 和 Worker 使用同一个EventLoopGroup undefined 多线程模型EventLoopGroup 包含多个 EventLoopBoss 和 Worker 使用同一个EventLoopGroup undefined 主从多线程模型EventLoopGroup 包含多个 EventLoopBoss 是主 ReactorWorker 是从 Reactor它们分别使用不同的 EventLoopGroup主 Reactor 负责新的网络连接 Channel 创建然后把 Channel 注册到从 Reactor。 事件调度层负责监听网络连接和读写操作然后触发各种类型的网络事件需要一种机制管理这些错综复杂的事件并有序地执行 服务编排层 服务编排层的职责是负责组装各类服务它是 Netty 的核心处理链用以实现网络事件的动态编排和有序传播。 服务编排层的核心组件包括 ChannelPipeline、ChannelHandler、ChannelHandlerContext。 ChannelPipeline ChannelPipeline 是 Netty 的核心编排组件负责组装各种 ChannelHandler实际数据的编解码以及加工处理操作都是由 ChannelHandler 完成的。 ChannelPipeline 可以理解为ChannelHandler 的实例列表——内部通过双向链表将不同的 ChannelHandler 链接在一起。当 I/O 读写事件触发时ChannelPipeline 会依次调用 ChannelHandler 列表对 Channel 的数据进行拦截和处理。 ChannelPipeline 是线程安全的因为每一个新的 Channel 都会对应绑定一个新的 ChannelPipeline。一个 ChannelPipeline 关联一个 EventLoop一个 EventLoop 仅会绑定一个线程。 ChannelPipeline、ChannelHandler 都是高度可定制的组件。开发者可以通过这两个核心组件掌握对 Channel 数据操作的控制权。 结构图 ChannelPipeline 中包含 ● 入站 ChannelInboundHandler ● 出站 ChannelOutboundHandler 两种处理器我们结合客户端和服务端的数据收发流程来理解 Netty 的这两个概念。 客户端和服务端都有各自的 ChannelPipeline。 以客户端为例数据从客户端发向服务端该过程称为出站反之则称为入站。 数据入站会由一系列 InBoundHandler 处理然后再以相反方向的 OutBoundHandler 处理后完成出站。 我们经常使用的编码 Encoder 是出站操作解码 Decoder 是入站操作。 服务端接收到客户端数据后需要先经过 Decoder 入站处理后再通过 Encoder 出站通知客户端。 所以客户端和服务端一次完整的请求应答过程可以分为三个步骤客户端出站请求数据、服务端入站解析数据并执行业务逻辑、服务端出站响应结果。 ChannelHandler ChannelHandlerContext 数据的编解码工作以及其他转换工作实际都是通过 ChannelHandler 处理的。 站在开发者的角度最需要关注的就是 ChannelHandler我们很少会直接操作 Channel都是通过 ChannelHandler 间接完成。 Channel 与 ChannelPipeline 的关系 ● 每创建一个 Channel 都会绑定一个新的 ChannelPipelineChannelPipeline 中每加入一个 ChannelHandler 都会绑定一个 ChannelHandlerContext。 ● 由此可见ChannelPipeline、ChannelHandlerContext、ChannelHandler 三个组件的关系是密切相关的 每个 ChannelHandler 绑定ChannelHandlerContext 的作用是什么呢 ● ChannelHandlerContext 用于保存 ChannelHandler 上下文通过 ChannelHandlerContext 我们可以知道 ChannelPipeline 和 ChannelHandler 的关联关系。 ● ChannelHandlerContext 可以实现 ChannelHandler 之间的交互ChannelHandlerContext 包含了 ChannelHandler 生命周期的所有事件如 connect、bind、read、flush、write、close 等。 Future、回调和 ChannelHandler Netty的异步编程模型是建立在Future和回调的概念之上的而将事件派发到ChannelHandler 的方法则发生在更深的层次上。结合在一起这些元素就提供了一个处理环境使你的应用程序逻 辑可以独立于任何网络操作相关的顾虑而独立地演变。这也是 Netty 的设计方式的一个关键目标。 拦截操作以及高速地转换入站数据和出站数据都只需要你提供回调或者利用操作所返回的 Future。这使得链接操作变得既简单又高效并且促进了可重用的通用代码的编写。 Channel Channel 是 Java NIO 的一个基本构造。 它代表一个到实体如一个硬件设备、一个文件、一个网络套接字或者一个能够执 行一个或者多个不同的I/O操作的程序组件的开放连接如读操作和写操作 回调 。 目前可以把 Channel 看作是传入入站或者传出出站数据的载体。因此它可以 被打开或者被关闭连接或者断开连接。 数据的载体数据在Channel中进行传输使用前需判断Channel是否可读、可写等服务端成功绑定端口即Channel打开客户端成功连上服务端即Channel建立客户端断开服务端即Channel断开。 回调 一个回调其实就是一个方法一个指向已经被提供给另外一个方法的方法的引用。这使得后者可以在适当的时候调用前者。回调在广泛的编程场景中都有应用而且也是在操作完成后通 知相关方最常见的方式之一。 Netty 在内部使用了回调来处理事件当一个回调被触发时相关的事件可以被一个 interfaceChannelHandler 的实现处理。Netty中一个新的连接已经被建立时 ChannelHandler 的 channelActive()回调方法将会被调用。 Future Future 提供了另一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作的结果的占位符它将在未来的某个时刻完成并提供对其结果的访问。 JDK 预置了 interface java.util.concurrent.Future但是其所提供的实现只 允许手动检查对应的操作是否已经完成或者一直阻塞直到它完成。这是非常繁琐的所以 Netty 提供了它自己的实现——ChannelFuture用于在执行异步操作的时候使用。 ChannelFuture提供了几种额外的方法这些方法使得我们能够注册一个或者多个 ChannelFutureListener实例。监听器的回调方法operationComplete()将会在对应的 操作完成时被调用 。然后监听器可以判断该操作是成功地完成了还是出错了。如果是后者我 们可以检索产生的Throwable。简而 言之 由ChannelFutureListener提供的通知机制消除 了手动检查对应的操作是否完成的必要。 每个 Netty 的出站 I/O 操作都将返回一个 ChannelFuture也就是说它们都不会阻塞。 正如我们前面所提到过的一样Netty 完全是异步和事件驱动的。 事件和 ChannelHandler Netty 使用不同的事件来通知我们状态的改变或者是操作的状态。这使得我们能够基于已经发生的事件来触发适当的动作。这些动作可能是 1、记录日志 2、数据转换 3、 流控制 4、应用程序逻辑。 Netty 是一个网络编程框架所以事件是按照它们与入站或出站数据流的相关性进行分类的。 可能由入站数据或者相关的状态更改而触发的事件包括 1、连接已被激活或者连接失活 2、数据读取 3、用户事件 4、错误事件 出站事件是未来将会触发的某个动作的操作结果这些动作包括 1、打开或者关闭到远程节点的连接 2、将数据写到或者冲刷到套接字。 每个事件都可以被分发给 ChannelHandler 类中的某个用户实现的方法。这是一个很好的将事件驱动范式直接转换为应用程序构件块的例子。 选择器、事件和 EventLoop Netty 通过触发事件将 Selector 从应用程序中抽象出来消除了所有本来将需要手动编写 的派发代码。在内部将会为每个 Channel 分配一个 EventLoop用以处理所有事件包括 1注册感兴趣的事件 2将事件派发给 ChannelHandler 3、安排进一步的动作。 EventLoop 本身只由一个线程驱动其处理了一个 Channel 的所有 I/O 事件并且在该 EventLoop 的整个生命周期内都不会改变。这个简单而强大的设计消除了你可能有的在 ChannelHandler 实现中需要进行同步的任何顾虑因此你可以专注于提供正确的逻辑用来在有感兴趣的数据要处理的时候执行。 网络通信层 在网络通信层有三个核心组件Bootstrap、ServerBootStrap、Channel Bootstrap负责客户端启动并用来链接远程Netty Server ServerBootStrap负责服务端监听用来监听指定端口 Channel相当于完成网络通信的载体。 事件调度层 事件调度器有两个核心组件EventLoopGroup与EventLoop EventLoopGroup本质上是一个线程池主要负责接收I/O请求并分配线程执行处理请求。 EventLoop相当于线程池中的线程 服务编排层 在服务编排层有三个核心组件ChannelPipeline、ChannelHandler、ChannelHandlerContext ChannelPipeline负责将多个ChannelHandler链接在一起 ChannelHandler针对I/O的数据处理器数据接收后通过指定的Handler进行处理。 ChannelHandlerContext用来保存ChannelHandler的上下文信息 ChannelHandler的各种 ChannelInboundHandlerAdapter ChannelInboundHandlerAdapter是ChannelInboundHandler的一个简单实现默认情况下不会做任何处理只是简单的将操作通过fire方法传递到ChannelPipeline中的下一个ChannelHandler中让链中的下一个ChannelHandler去处理。 需要注意的是信息经过channelRead方法处理之后不会自动释放因为信息不会被自动释放所以能将消息传递给下一个ChannelHandler处理。 SimpleChannelInboundHandler SimpleChannelInboundHandler支持泛型的消息处理默认情况下消息处理完将会被自动释放无法提供fire方法传递给ChannelPipeline中的下一个ChannelHandler,如果想要传递给下一个ChannelHandler需要调用ReferenceCountUtil#retain方法。 channelRead0方法在将来将会重命名为messageReceived ChannelInitializer类图 需要注意的是 a. ChannelInitializer继承于ChannelInboundHandler接口 b. ChannelInitializer是一个抽象类不能直接使用 2. initChannel抽象方法 ChannelInitializer中声明了一个名为initChannel的抽象方法 /*** This method will be called once the {link Channel} was registered. After the method returns this instance* will be removed from the {link ChannelPipeline} of the {link Channel}.** param ch the {link Channel} which was registered.* throws Exception is thrown if an error occurs. In that case it will be handled by* {link #exceptionCaught(ChannelHandlerContext, Throwable)} which will by default close* the {link Channel}.*/ protected abstract void initChannel(C ch) throws Exception;ChannelInitializer的实现类必须要重写这个方法这个方法在Channel被注册到EventLoop的时候会被调用 3. ChannelInitializer什么时候会被调用 以ServerBootstrap启动这一场景为例 在ServerBootstrap.init()方法中负责accept新链接的Channel的pipeline被添加了一个ChannelInitializerp.addLast(new ChannelInitializerChannel() {Overridepublic void initChannel(final Channel ch) throws Exception {final ChannelPipeline pipeline ch.pipeline();ChannelHandler handler config.handler();if (handler ! null) {pipeline.addLast(handler);}ch.eventLoop().execute(new Runnable() {Overridepublic void run() {pipeline.addLast(new ServerBootstrapAcceptor(ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));}});} });由于此时这个Channel还没有被register到EventLoop于是在addLast方法的调用链中会给pipeline添加一个PendingHandlerAddedTask其目的是在Channel被register到EventLoop的时候触发一个回调事件 然后在AbstractBootstrap.initAndRegister()方法中这个Channel会被register到boss EventLoopGoup接着会被register到boss EventLoopGoup中的某一个具体的EventLoop 在AbstractChannel.register0()方法中之前注册的PendingHandlerAddedTask会被调用经过一系列调用之后ChannelInitializer.handleAdded()方法会被触发 /*** {inheritDoc} If override this method ensure you call super!*/Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {if (ctx.channel().isRegistered()) {// This should always be true with our current DefaultChannelPipeline implementation.// The good thing about calling initChannel(...) in handlerAdded(...) is that there will be no ordering// surprises if a ChannelInitializer will add another ChannelInitializer. This is as all handlers// will be added in the expected order.initChannel(ctx);}}SuppressWarnings(unchecked)private boolean initChannel(ChannelHandlerContext ctx) throws Exception {if (initMap.putIfAbsent(ctx, Boolean.TRUE) null) { // Guard against re-entrance.try {initChannel((C) ctx.channel());//调用子类重写的initChannel方法} catch (Throwable cause) {// Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).// We do so to prevent multiple calls to initChannel(...).exceptionCaught(ctx, cause);} finally {remove(ctx);//将ChannelInitializer从pipeline中移除}return true;}return false;}/*** This method will be called once the {link Channel} was registered. After the method returns this instance* will be removed from the {link ChannelPipeline} of the {link Channel}.** param ch the {link Channel} which was registered.* throws Exception is thrown if an error occurs. In that case it will be handled by* {link #exceptionCaught(ChannelHandlerContext, Throwable)} which will by default close* the {link Channel}.*/protected abstract void initChannel(C ch) throws Exception;private void remove(ChannelHandlerContext ctx) {try {ChannelPipeline pipeline ctx.pipeline();if (pipeline.context(this) ! null) {pipeline.remove(this);}} finally {initMap.remove(ctx);}}大概意思是 a. 触发ChannelInitializer的initChannel方法执行子类定义的一系列操作在ServerBootstrap这个例子中就是将ServerBootstrapAcceptor注册到pipeline中 b. 将ChannelInitializer从pipeline中移除 ChannelInitializer的主要目的是为程序员提供了一个简单的工具用于在某个Channel注册到EventLoop后对这个Channel执行一些初始化操作。ChannelInitializer虽然会在一开始会被注册到Channel相关的pipeline里但是在初始化完成之后ChannelInitializer会将自己从pipeline中移除不会影响后续的操作。 使用场景 a. 在ServerBootstrap初始化时为监听端口accept事件的Channel添加ServerBootstrapAcceptor b. 在有新链接进入时为监听客户端read/write事件的Channel添加用户自定义的ChannelHandler Protocol Support 协议支持层 协议支持层基本上覆盖了主流协议的编解码实现 HTTP SSL Protobuf 压缩 大文件传输 WebSocket 文本 二进制 等主流协议此外 Netty 还支持自定义应用层协议。 自定义应用层协议 Netty 丰富的协议支持降低了用户的开发成本基于 Netty 我们可以快速开发 HTTP、WebSocket 等服务。 Transport Service 传输服务层 传输服务层提供了网络传输能力的定义和实现方法。 它支持 Socket HTTP 隧道 虚拟机管道 等传输方式。 Netty 对 TCP、UDP 等数据传输做了抽象和封装用户可以更聚焦在业务逻辑实现上而不必关系底层数据传输的细节。 Netty 的模块设计具备较高的通用性和可扩展性它不仅是一个优秀的网络框架还可以作为网络编程的工具箱。Netty 的设计理念非常优雅值得我们学习借鉴。 组件的整体交互流程 ● 服务端启动初始化时有 Boss EventLoopGroup 和 Worker EventLoopGroup 两个组件其中 Boss 负责监听网络连接事件。当有新的网络连接事件到达时则将 Channel 注册到 Worker EventLoopGroup。 ● Worker EventLoopGroup 会被分配一个 EventLoop 负责处理该 Channel 的读写事件。每个 EventLoop 都是单线程的通过 Selector 进行事件循环。 ● 当客户端发起 I/O 读写事件时服务端 EventLoop 会进行数据的读取然后通过 Pipeline 触发各种监听器进行数据的加工处理。 ● 客户端数据会被传递到 ChannelPipeline 的第一个 ChannelInboundHandler 中数据处理完成后将加工完成的数据传递给下一个 ChannelInboundHandler。 ● 当数据写回客户端时会将处理结果在 ChannelPipeline 的 ChannelOutboundHandler 中传播最后到达客户端。 以上便是 Netty 各个组件的整体交互流程你只需要对每个组件的工作职责有所了解心中可以串成一条流水线即可 源码结构 我们不仅可以使用 Netty all-in-one 的 Jar 包也可以单独使用其中某些工具包。下面我根据 Netty 的分层结构以及实际的业务场景具体介绍 Netty 中常用的工具包。 Core 核心层模块 GitHubhttps://github.com/netty/netty查询 Netty 的源码。 netty-common模块 Netty 的核心基础包提供了丰富的工具类其他模块都需要依赖它。在 common 模块中常用的包括通用工具类和自定义并发包。 ● 通用工具类比如定时器工具 TimerTask、时间轮 HashedWheelTimer 等。 ● 自定义并发包比如异步模型****Future Promise、相比 JDK 增强的 FastThreadLocal 等。 netty-buffer 模块 Netty自己实现了的一个更加完备的ByteBuf 工具类用于网络通信中的数据载体。由于人性化的 Buffer API 设计它已经成为 Java ByteBuffer 的完美替代品。ByteBuf 的动态性设计不仅解决了 ByteBuffer 长度固定造成的内存浪费问题而且更安全地更改了 Buffer 的容量。此外 Netty 针对 ByteBuf 做了很多优化例如缓存池化、减少数据拷贝的 CompositeByteBuf 等。 netty-resover模块 主要提供了一些有关基础设施的解析工具包括 IP Address、Hostname、DNS 等。 Protocol Support 协议支持层模块 netty-codec模块 主要负责编解码工作通过编解码实现原始字节数据与业务实体对象之间的相互转化。 如下图所示Netty 支持了大多数业界主流协议的编解码器如 HTTP、HTTP2、Redis、XML 等为开发者节省了大量的精力。 此外该模块提供了抽象的编解码类 ByteToMessageDecoder 和 MessageToByteEncoder通过继承这两个类我们可以轻松实现自定义的编解码逻辑。 netty-handler模块 主要负责数据处理工作。 Netty 中关于数据处理的部分本质上是一串有序 handler 的集合。 netty-handler 模块提供了开箱即用的 ChannelHandler 实现类例如日志、IP 过滤、流量整形等如果你需要这些功能仅需在 pipeline 中加入相应的 ChannelHandler 即可。 Transport Service 传输服务层模块 netty-transport 模块 可以说是 Netty 提供数据处理和传输的核心模块。 该模块提供了很多非常重要的接口如 Bootstrap、Channel、ChannelHandler、EventLoop、EventLoopGroup、ChannelPipeline 等。 ● Bootstrap 负责客户端或服务端的启动工作包括创建、初始化 Channel 等 ● EventLoop 负责向注册的 Channel 发起 I/O 读写操作 ● ChannelPipeline 负责 ChannelHandler 的有序编排。 这些组件在介绍 Netty 逻辑架构的时候都有所涉及。 Netty是如何处理连接请求和业务逻辑的呢 – Channels、Events 和 IO Netty是一个非阻塞的、事件驱动的、网络编程框架。当然我们很容易理解Netty会用线程来处理IO事件对于熟悉多线程编程的人来说你或许会想到如何同步你的代码但是Netty不需要我们考虑这些具体是这样 一个Channel会对应一个EventLoop而一个EventLoop会对应着一个线程也就是说仅有一个线程在负责一个Channel的IO操作。 关于这些名词之间的关系可以见下图 如图所示当一个连接到达Netty会注册一个channel然后EventLoopGroup会分配一个EventLoop绑定到这个channel,在这个channel的整个生命周期过程中都会由绑定的这个EventLoop来为它服务而这个EventLoop就是一个线程。 说到这里那么EventLoops和EventLoopGroups关系是如何的呢我们前面说过一个EventLoopGroup包含多个Eventloop但是我们看一下下面这幅图这幅图是一个继承树从这幅图中我们可以看出EventLoop其实继承自EventloopGroup也就是说在某些情况下我们可以把一个EventLoopGroup当做一个EventLoop来用。 我们来看看如何配置一个Netty应用-- BootsStrapping 我们利用BootsStrapping来配置netty 应用它有两种类型一种用于Client端BootsStrap另一种用于Server端ServerBootstrap要想区别如何使用它们你仅需要记住一个用在Client端一个用在Server端。下面我们来详细介绍一下这两种类型的区别 1.第一个最明显的区别是ServerBootstrap用于Server端通过调用bind()方法来绑定到一个端口监听连接Bootstrap用于Client端需要调用connect()方法来连接服务器端但我们也可以通过调用bind()方法返回的ChannelFuture中获取Channel去connect服务器端。 2.客户端的Bootstrap一般用一个EventLoopGroup而服务器端的ServerBootstrap会用到两个这两个也可以是同一个实例。为何服务器端要用到两个EventLoopGroup呢这么设计有明显的好处如果一个ServerBootstrap有两个EventLoopGroup那么就可以把第一个EventLoopGroup用来专门负责绑定到端口监听连接事件而把第二个EventLoopGroup用来处理每个接收到的连接下面我们用一幅图来展现一下这种模式 PS: 如果仅由一个EventLoopGroup处理所有请求和连接的话在并发量很大的情况下这个EventLoopGroup有可能会忙于处理已经接收到的连接而不能及时处理新的连接请求用两个的话会有专门的线程来处理连接请求不会导致请求超时的情况大大提高了并发处理能力。 我们知道一个Channel需要由一个EventLoop来绑定而且两者一旦绑定就不会再改变。一般情况下一个EventLoopGroup中的EventLoop数量会少于Channel数量那么就很有可能出现一个多个Channel公用一个EventLoop的情况这就意味着如果一个Channel中的EventLoop很忙的话会影响到这个Eventloop对其它Channel的处理这也就是为什么我们不能阻塞EventLoop的原因。 当然我们的Server也可以只用一个EventLoopGroup,由一个实例来处理连接请求和IO事件请看下面这幅图 我们看看Netty是如何处理数据的-- Netty核心ChannelHandler 下面我们来看一下netty中是怎样处理数据的回想一下我们前面讲到的Handler对了就是它。说到Handler我们就不得不提ChannelPipelineChannelPipeline负责安排Handler的顺序及其执行下面我们就来详细介绍一下他们 ChannelPipeline and handlers 我们的应用程序中用到的最多的应该就是ChannelHandler我们可以这么想象数据在一个ChannelPipeline中流动而ChannelHandler便是其中的一个个的小阀门这些数据都会经过每一个ChannelHandler并且被它处理。这里有一个公共接口ChannelHandler: 从上图中我们可以看到ChannelHandler有两个子类ChannelInboundHandler和ChannelOutboundHandler这两个类对应了两个数据流向如果数据是从外部流入我们的应用程序我们就看做是inbound相反便是outbound。其实ChannelHandler和Servlet有些类似一个ChannelHandler处理完接收到的数据会传给下一个Handler或者什么不处理直接传递给下一个。下面我们看一下ChannelPipeline是如何安排ChannelHandler的 从上图中我们可以看到一个ChannelPipeline可以把两种HandlerChannelInboundHandler和ChannelOutboundHandler混合在一起当一个数据流进入ChannelPipeline时它会从ChannelPipeline头部开始传给第一个ChannelInboundHandler当第一个处理完后再传给下一个一直传递到管道的尾部。与之相对应的是当数据被写出时它会从管道的尾部开始先经过管道尾部的“最后”一个ChannelOutboundHandler当它处理完成后会传递给前一个ChannelOutboundHandler。 数据在各个Handler之间传递这需要调用方法中传递的ChanneHandlerContext来操作 在netty的API中提供了两个基类分ChannelOutboundHandlerAdapter和ChannelOutboundHandlerAdapter他们仅仅实现了调用ChanneHandlerContext来把消息传递给下一个Handler因为我们只关心处理数据因此我们的程序中可以继承这两个基类来帮助我们做这些而我们仅需实现处理数据的部分即可。 我们知道InboundHandler和OutboundHandler在ChannelPipeline中是混合在一起的那么它们如何区分彼此呢其实很容易因为它们各自实现的是不同的接口对于inbound eventNetty会自动跳过OutboundHandler,相反若是outbound eventChannelInboundHandler会被忽略掉。 当一个ChannelHandler被加入到ChannelPipeline中时它便会获得一个ChannelHandlerContext的引用而ChannelHandlerContext可以用来读写Netty中的数据流。因此现在可以有两种方式来发送数据一种是把数据直接写入Channel一种是把数据写入ChannelHandlerContext它们的区别是写入Channel的话数据流会从Channel的头开始传递而如果写入ChannelHandlerContext的话数据流会流入管道中的下一个Handler。 我们最关心的部分如何处理我们的业务逻辑 – Encoders, Decoders and Domain Logic Netty中会有很多Handler具体是哪种Handler还要看它们继承的是InboundAdapter还是OutboundAdapter。当然Netty中还提供了一些列的Adapter来帮助我们简化开发我们知道在Channelpipeline中每一个Handler都负责把Event传递给下一个Handler如果有了这些辅助Adapter这些额外的工作都可自动完成我们只需覆盖实现我们真正关心的部分即可。此外还有一些Adapter会提供一些额外的功能比如编码和解码。那么下面我们就来看一下其中的三种常用的ChannelHandler Encoders和Decoders 因为我们在网络传输时只能传输字节流因此才发送数据之前我们必须把我们的message型转换为bytes与之对应我们在接收数据后必须把接收到的bytes再转换成message。我们把bytes to message这个过程称作Decode(解码成我们可以理解的)把message to bytes这个过程成为Encode。 Netty中提供了很多现成的编码/解码器我们一般从他们的名字中便可知道他们的用途如ByteToMessageDecoder、MessageToByteEncoder如专门用来处理Google Protobuf协议的ProtobufEncoder、 ProtobufDecoder。 我们前面说过具体是哪种Handler就要看它们继承的是InboundAdapter还是OutboundAdapter对于Decoders,很容易便可以知道它是继承自ChannelInboundHandlerAdapter或 ChannelInboundHandler因为解码的意思是把ChannelPipeline传入的bytes解码成我们可以理解的message即Java Object而ChannelInboundHandler正是处理Inbound Event而Inbound Event中传入的正是字节流。Decoder会覆盖其中的“ChannelRead()”方法在这个方法中来调用具体的decode方法解码传递过来的字节流然后通过调用ChannelHandlerContext.fireChannelRead(decodedMessage)方法把编码好的Message传递给下一个Handler。与之类似Encoder就不必多少了。 Domain Logic 其实我们最最关心的事情就是如何处理接收到的解码后的数据我们真正的业务逻辑便是处理接收到的数据。Netty提供了一个最常用的基类SimpleChannelInboundHandler其中T就是这个Handler处理的数据的类型上一个Handler已经替我们解码好了消息到达这个Handler时Netty会自动调用这个Handler中的channelRead0(ChannelHandlerContext,T)方法T是传递过来的数据对象在这个方法中我们便可以任意写我们的业务逻辑了 Netty中Pipeline工作原理 1、结构设计 Netty中的Pipeline本质上是一个双向链表它采用了责任链模式。在Netty中每个Channel都有且仅有一 个ChannelPipeline与之对应一个Channel包含了一个ChannelPipeline而ChannelPipeline中又维护了一个由ChannelHandlerContext组成的双向链表。这个链表的头叫HeadContext链表的尾叫TailContext并且每个ChannelHandlerContext中又关联着一个ChannelHandler。对于用过Netty的小伙伴来说应该非常熟悉。在Netty中Pipeline的初始化是通过调用Channel的handler() 方法,然后在handler()方法中传入一个叫做ChannelInitializer的对象通过SocketChannel构建出一个新的Pipeline对象。每次调用addLast()方法都会在Pipelie的末端插入一个ChannelHandlerContext。如图所示每个Context中又会包含一个ChannelHandler我们通过addLast()方法往Pipeline中添加的对象并且 Handler的添加顺序会影响代码的执行顺序。而这些Handler本质上都是实现编码和解码的功能不管是编码器还是解码器都必须实现ChannelHandler接口。 图中的Handler就是我们代码程序要执行的逻辑。而Netty默认帮我们实现了非常多内置Handler我们只需要 直接拿过来用就可以了。当然我们也可以自己实现ChannelHandler接口来实现自定义的编、码器。比如自定义通信协议等等。 当所有的Handler全部添加到Pipeline中以后Netty就会将这些Handler组装成一个双向链表从而实现串行 化调用。从头部往尾部执行的Handler被称为Inbound用来接收用户请求从尾部往头部执行的Handler被称为Outbound用来给用户响应。所以Inbound可以用来实现解码的功能、而Outbound可以用来实现编码的功能。
http://www.pierceye.com/news/234738/

相关文章:

  • 深圳网站建设平台网站右侧浮动广告
  • 中英文网站源码浙江东南网架公司
  • 个人备案网站放什么资料培训
  • html做企业门户网站提供设计的网站
  • 成都三合一网站建设成年s8视频加密线路
  • 做网站购买服务器如何优化网络
  • 企业公司网站 北京怎样用前端知识制作企业网站
  • 精湛的赣州网站建设襄阳哪里有做网站的
  • 拿了网赌代理后怎样做自己的网站河南最新消息今天
  • 北京最大的网站开发公司中山市企业网站seo营销工具
  • 苏州营销型网站建设方案哪些网站做的比较好的
  • 淘宝上买的建设网站能退款吗app怎么查网站备案
  • 电子商务网站开发与设计报告专业网站建设公司兴田德润怎么样
  • 如何建立p2p网站win2003怎么做网站
  • 免费网页设计制作网站建筑公司愿景口号大全
  • 个人可以做网站维护吗专业团队电脑壁纸
  • 东营专业网站建设公司排行鞍山市人力资源招聘信息网
  • 郑州网站建设蝶动小公司使用的网站开发
  • 合肥网站seo技术软件开发工程师简历模板
  • org的域名网站在线取公司名字 免费
  • 网站开发有哪几个阶段百度网站官网怎么做
  • 微信网站名域名访问网站怎么下载
  • 网站源码怎么预览建站技巧
  • 织梦网站会员功能化妆品网站建设描述
  • 手机app软件定制马鞍山seo
  • 重庆网站建设 九度互联响应式网站开发工具
  • 句容市建设工程管理处网站wordpress联系表格
  • 电商网站建设流程新能源汽车价格一览表
  • 实验室网站建设的调查报告海报设计图片手绘图
  • 征求网站建设买正品东西哪个网最好