博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Netty4学习笔记(4)-- ByteBuf和设计模式

Posted on 2016-04-28 18:11  bw_0927  阅读(149)  评论(0)    收藏  举报

http://blog.csdn.net/zxhoo/article/details/17577865

 

ByteBuf逻辑结构

正如类名所反映出来的,ByteBuf逻辑上就是一个byte容器。ByteBuf里的数据被两个指针划分为三个部分,如下图所示:

  • reader index前面的数据是已经读过的数据,这些数据可以扔掉
  • 从reader index开始,到writer index之前的数据是可读数据
  • 从writer index开始,为可写区域

正是因为这样的设计,ByteBuf可以同时读写数据(只要可读区域和可写区域都还有空闲空间),而java.nio.ByteBuffer则必须调用flip()方法才能从写状态切换到读状态。

 

 

ByteBufAllocator - 抽象工厂模式

在Netty的世界里,ByteBuf实例通常应该由ByteBufAllocator来创建。ByteBuf和Allocator的关系如下图所示:

Allocator的buffer()方法创建ByteBuf实例,ByteBuf的alloc()方法返回创建自己的Allocator。ByteBufAllocator的实现使用了抽象工厂模式,如下图所示:

 

CompositeByteBuf - 组合模式

CompositeByteBuf可以让我们把多个ByteBuf当成一个大Buf来处理,ByteBufAllocator提供了compositeBuffer()工厂方法来创建CompositeByteBuf。CompositeByteBuf的实现使用了组合模式,如下图所示:

ByteBufInputStream - 适配器模式

ByteBufInputStream使用适配器模式,使我们可以把ByteBuf当做Java的InputStream来使用。同理,ByteBufOutputStream允许我们把ByteBuf当做OutputStream来使用。

比如说我们要实现一个自定义的消息协议,消息包括header和body两部分内容,body里放的是JSON字符串。那么就可以使用ByteBufInputStream来避免把ByteBuf里的字节拷贝到字节数组的开销:

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. private Object decodeMessage(ByteBuf bb) {  
  2.     // read header  
  3.     // bb.readXxx()...  
  4.       
  5.     // read body  
  6.     InputStreamReader reader = new InputStreamReader(new ByteBufInputStream(bb));  
  7.     return new Gson().fromJson(reader, JsonObject.class);  
  8. }  

 

 

ReadOnlyByteBuf - 装饰器模式

ReadOnlyByteBuf用适配器模式把一个ByteBuf变为只读,ReadOnlyByteBuf通过调用Unpooled.unmodifiableBuffer(ByteBuf)方法获得:

 

类似的ByteBuf适配器还包括:

 

ByteBuf - 工厂方法模式

前面也提到过了,我们很少需要直接通过构造函数来创建ByteBuf实例,而是通过Allocator来创建。从装饰器模式可以看出另外一种获得ByteBuf的方式是调用ByteBuf的工厂方法,比如:

  • ByteBuf#duplicate() 
  • ByteBuf#slice()

 

ByteBufProcessor - 访问者模式还是迭代器模式?

最后,ByteBuf提供了4个forEachByte()方法来对ByteBuf里的数据进行某种处理或查找,看起来像是访问者模式迭代器模式的混合:

  • public abstract int forEachByte(ByteBufProcessor processor);
  • public abstract int forEachByte(int index, int length, ByteBufProcessor processor);
  • public abstract int forEachByteDesc(ByteBufProcessor processor);
  • public abstract int forEachByteDesc(int index, int length, ByteBufProcessor processor);