介绍Netty为什么这么好,它在JDK自带NIO的基础上做了哪些改进?它的架构和工作流程如何?请进入今天的netty系列文章:netty架构概述。Netty架构图netty的主要功能是提供一个简单的NIO框架,可以在上层结合各种协议最终实现一个高性能的服务器。下面是netty官网提供的架构图:从上图我们可以看出netty的核心主要分为三个部分,分别是可扩展的事件模型、统一的API、强大的ByteBuffer。这三个特性是netty的法宝。下面将从这几个方面来详细描述netty的特点,让读者了解netty的优秀之处。丰富的Buffer数据组织从底层Buffer数据结构开始。Netty提供了一个io.netty.buffer包,它定义了各种类型的ByteBuf及其派生类型。nettyBuffer的基础是ByteBuf类,它是一个抽象类。其他的Buffer类基本都是派生自这个类。这个类也定义了netty整体Buffer的基调。netty重写ByteBuf的目的是为了让底层的ByteBuf比JDK自带的更快,更适合扩展。具体来说,netty的ByteBuf比JDK中的ByteBuffer速度更快,同时更容易扩展,可以根据需要自定义Buf。另外netty内置了一些复合缓冲区类型,可以实现透明的零拷贝。对于动态缓冲区类型,可以像StringBuffer一样按需扩展,非常好用。零拷贝什么是零拷贝?零拷贝意味着当需要拷贝时不进行拷贝。我们知道数据在使用底层协议传输的过程中会被封装成一个个的数据包进行传输。当传输的数据太大而无法放在一个数据包中时,就需要对数据进行拆分。目的方接收到数据后,需要对接收到的数据进行组装。一般来说,这种组装操作是针对数据的。复制,将拆分后的对象复制到一个长数据空间。比如下面这个例子,底层的TCP包调用了顶层的HTTP包,但是没有复制:怎么复制呢?在上一篇文章中,我们知道netty提供了一个工具类方法Unpooled。这个工具类里面有很多wrapped开头的方法。让我们举几个例子:publicstaticByteBufwrappedBuffer(byte[]...arrays){}publicstaticByteBufwrappedBuffer(ByteBuf...buffers){returnwrappedBuffer(buffers.length,buffers);}publicstaticByteBufwrappedBuffer(ByteBuffer...buffers){returnwrappedBuffer.buffers(length,buffers);}以上三个方法分别是封装字节数组、封装ByteBuf和封装ByteBuffer,都是零拷贝。大家可以在实际项目中根据实际情况进行选择。统一的API一般而言,在传统的JDKIOAPI中,根据传输类型或协议的不同,使用的API是不同的。不同的传输方式需要开发不同的应用,不能统一。这样做的结果是无法顺利迁移,程序扩展时需要额外处理。传输方式是什么?这里指的是实现IO的方式,比如传统的阻塞IO,我们可以称之为OIO,java的新IO可以称之为NIO,异步IO可以称之为AIO等等。而JDK中传统的IO和NIO是分开的。如果你一开始使用传统IO,当你的客户数量增长到一定程度,你准备切换到NIO时,你会发现切换极其复杂,因为它们是分立的。为了解决这个问题,netty提供了一个统一的类Channel来提供统一的API。首先看Channel中定义的方法:从上图我们可以看出,使用Channel可以判断通道的当前状态,配置它的参数,对其进行I/O操作,使用与Channel相关的ChannelPipelinechannel处理与通道关联的IO请求和事件。使用Channel可以很好的支持NIO的TCP/IP、OIO的TCP/IP、OIO的UDP/IP和本地传输。传输方式的切换只需更换,成本很小。当然,如果你对现有的实现不满意,你也可以对核心API进行自定义扩展。Event-drivennetty是一个事件驱动的框架。事件驱动框架的基础是事件模型。Netty专门为IO定义了一个非常有效的事件模型。可以在不破坏现有代码的情况下实现您自己的事件类型。netty中的自定义事件类型以严格的类型层次区别于其他事件类型,因此具有很强的可扩展性。netty中的事件驱动是ChannelEvent、ChannelHandler和ChannelPipeline共同作用的结果。其中ChannelEvent表示发生的事件,ChannelHandler定义了如何处理事件,而ChannelPipeline类似于一个拦截器,允许用户自己控制定义的ChannelHandler,从而达到控制事件处理的结果。让我们看一个简单的自定义Handler:try{log.info("收到消息:{}",in.toString(io.netty.util.CharsetUtil.US_ASCII));}最后{ReferenceCountUtil.release(msg);}}@OverridepublicvoidexceptionCaught(ChannelHandlerContextctx,Throwablecause){//异常处理cause.printStackTrace();ctx.close();}}在上面的例子中,我们定义了如何处理接收到的消息和异常。在后续文章中,我们将详细介绍ChannelEvent、ChannelHandler和ChannelPipeline之间的交互。其他优秀的特性除了上面提到的三个核心特性,netty还有其他几个方便程序员开发的优点。比如对SSL/TLS的支持、HTTP协议的实现、WebSockets和GoogleProtocolBuffers的实现等等,都表明netty在各种场景下都具有强大的应用能力。总结一下,netty由三个核心组件组成:buffer、channel和eventmodel。通过了解这三个核心组件如何相互协作,不难理解构建在netty之上的高级功能。本文示例可参考:learn-netty4本文已收录于http://www.flydean.com/03-netty-architecture/最流行的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等你来发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!
