Netty 4.1中的新变化和注意点

目录 [−]

  1. 题外话
  2. 核心改变
    1. Android支持
    2. ChannelHandlerContext.attr(..) == Channel.attr(..)
    3. Channel.hasAttr(...)
    4. 更容易更精确的追踪buffer leak
    5. PooledByteBufAllocator作为默认的buffer allocator
    6. 全局唯一的 channel ID
    7. 更灵活的线程模型
    8. EmbeddedChannel 可用性
    9. 能够使用Executor替换ThreadFactory
    10. 更友好的类加载器 Class loader friendliness
    11. ByteBufAllocator.calculateNewCapacity()
  3. 新的编解码和handler
  4. 其它编解码的改变
    1. AsciiString
    2. TextHeaders
    3. MessageAggregator
    4. HttpObjectAggregator更好的处理超出尺寸的消息
    5. ChunkedInput 和 ChunkedWriteHandler
    6. SnappyFramedEncoder 和 SnappyFramedDecoder

本文翻译自官方文档New and noteworthy in 4.1

本文带你了解Netty 4.0到Netty 4.1的值得注意的改变和新特性.

题外话

尽管我们尽量保持向下兼容,4.1 还是有一些和4.0不完全兼容的地方. 请确保使用新的Netty版本重新编译你的应用.
当你重新编译你的应用时,你可以能看到一些弃用警告. 请依照修改建议来更正它们, 这样当你升级到新的版本时会遇到较少的麻烦.

核心改变

Android支持

考虑到:

  • 移动设备日益强大
  • 自 Ice Cream Sandwich版本后ADK中大部分NIO 和 SSLEngine的问题都被修复
  • 用户很想在移动应用中重用它们的编解码器和handler

我们决定官方的支持 Android (4.0 及以上版本) .
然而,我们并没有一个为Android提供的测试套件. 如果你发现在Android使用的问题, 请提交一个 issue. 也请考虑贡献Android的测试代码作为整个构建过程的一部分.

ChannelHandlerContext.attr(..) == Channel.attr(..)

ChannelChannelHandlerContext实现了 AttributeMap接口, 允许用户附加一个或者多个属性在它们上. 有时候用户迷惑的是[ChannelChannelHandlerContext用户自己的属性存储. 例如,即使你通过Channel.attr(KEY_X).set(valueX)设置一个属性'KEY_X' , 你也不会通过ChannelHandlerContext.attr(KEY_X).get()得到这个属性, 相反亦然. 这种行为不仅让人迷惑,而且也浪费内存.

为了解决这个问题, 我们决定为每个Channel在内部只保留一个map. AttributeMap总是使用AttributeKey 作为它的主键. AttributeKey确保主键的唯一性, 这样每个Channel不会有多余一个的attribute map. 由于用户会将他们自己的主键定义为 ChannelHandler的private static final 字段 , 不会有重复的键值的担忧.

Channel.hasAttr(...)

现在我们可以有效地检查一个属性是否存在.

更容易更精确的追踪buffer leak

先前, 找到buffer泄漏并不容易,泄漏警告不太有帮助. 现在我们有了一个先进的泄漏报告机制,当开销增加时会被启用。(We now have an advanced leak reporting mechanism which can be enabled at the cost of increased overhead.)

查看Reference counted objects得到更多信息 . 这个特性太重要了,所以也被增加回 4.0.14.

PooledByteBufAllocator作为默认的buffer allocator

在 4.x 中, 尽管有一些功能局限性, UnpooledByteBufAllocator 曾是默认的allocator. 现在 PooledByteBufAllocator 已经使用了很长一段时间了,而且我们有了先进的buffer泄漏追踪机制,是时候把它作为默认的buffer allocator了.

现在PooledByteBufAllocator 是默认的buffer allocator.

全局唯一的 channel ID

每个Channel都有一个唯一的ID,依据一下信息产生:

  • MAC 地址 (EUI-48 or EUI-64),
  • 进程 ID,
  • System#currentTimeMillis()
  • System#nanoTime()
  • 一个随机的 32-bit integer
  • 一个顺序增加的32-bit integer.

Channe ID可以通过 Channel.id()方法得到.

更灵活的线程模型

一个新的ChannelHandlerInvoker 加入, 允许用户对哪个线程处理handler方法有更多的控制
作为往ChannelPipeline中增加ChannelHandler时指定EventExecutor的替代,指定一个定制的ChannelHandlerInvoker实现可以实现更多的控制.

想了解更多的信息,可以参考 commit 132af3a.

EmbeddedChannel 可用性

EmbeddedChannelreadInbound()readOutbound() 返回一个 特定类型的参数, 你不必将返回值在转型, 减少了单元测试代码的啰嗦.

1
2
3
4
5
6
7
EmbeddedChannel ch = ...;
// BEFORE:
FullHttpRequest req = (FullHttpRequest) ch.readInbound();
// AFTER:
FullHttpRequest req = ch.readInbound();

能够使用Executor替换ThreadFactory

一些应用要求用户运行他们的任务在一个指定的Executor. 而4.x在创建event loop时需要用户指定的是ThreadFactory ,现在已经用Executor替换了.

关于这个改变的更多信息,你可以查看 pull request #1762.

更友好的类加载器 Class loader friendliness

在容器环境中一些类型如AttributeKey对应用程序来说不是太友好,现在没有这个问题了.

ByteBufAllocator.calculateNewCapacity()

计算可扩展的ByteBuf容量的代码从AbstractByteBuf移到ByteBufAllocator, 因为ByteBufAllocator更方便的知道它管理的buffer的容量计算信息.

新的编解码和handler

  • Binary memcache protocol codec
  • Compression codecs
    * BZip2
    * FastLZ
    * LZ4
    * LZF
    
  • DNS protocol codec
  • HAProxy protocol codec
  • MQTT protocol codec
  • SPDY/3.1 support
  • STOMP codec
  • SOCKSx codec, 支持版本 4, 4a, 和 5; 查看 socksx包.
  • XmlFrameDecoder 允许处理XML文档流.
  • JsonObjectDecoder 允许处理JSON对象流.
  • IP filtering handlers

其它编解码的改变

AsciiString

AsciiString是一个新的CharSequence实现, 包含的字符只占1个字节. 当你处理US-ASCII 或者 ISO-8859-1 字符串时可以节省空间.

例如, HTTP 编解码器和STOMP编解码器使用AsciiString处理header name. 因为将AsciiString编码到ByteBuf中不会有类型转换的代价,比String类型有更好的性能.

TextHeaders

TextHeaders 提供了一个通用的数据结构,类似Http Header类型的字符串 mutimap. HttpHeaders也用TextHeaders重写.

MessageAggregator

MessageAggregator 为聚合多个小消息成一个大消息提供了通用的功能,就像HttpObjectAggregator实现的那样. HttpObjectAggregator使用MessageAggregator进行了重写.

HttpObjectAggregator更好的处理超出尺寸的消息

在4.0中在客户端发送消息前没有办法拒绝一个超过指定大小的HTTP 消息,即使 100-continue header已经设置.
4.1中增加了一个可以override方法,叫做handleOversizedMessage, 因此用户可以执行他想要的任务. 默认条件下, 它会返回一个 '413 Request Entity Too Large' response, 然后关闭连接.

ChunkedInputChunkedWriteHandler

ChunkedInput 有两个新的方法; progress()length() 返回数据传输的进度以及流的程度. ChunkedWriteHandler使用这个信息通知 ChannelProgressiveFutureListener.

SnappyFramedEncoderSnappyFramedDecoder

这两个类被改名为SnappyFrameEncoder and SnappyFrameDecoder. T老的类被标记为弃用, 实际上它们是新的类的子类.