设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

Netty 4.0的新特性及需要注意的地方

2013-4-7 10:45| 发布者: joejoe0332| 查看: 24321| 评论: 0|原作者: 开源中国社区|来自: 开源中国社区

摘要:   这篇文章和你一起过下Netty的主发行版本的一些显著的改变和新特性,让你在把你的应用程序转换到新版本的时候有个概念。 项目结构改变   Netty的包名从org.jboss.netty改为io.netty,因为我们不在是JBoss.org的 ...

Pooled ByteBuf

前面已经提到Netty引入了pooledByteBufinstances。这在很多方面都很实用,举列 如下:

  • 限制了GC压力,这是因为使用unpooled ByteBufs会造成沉重的分配与再分配问题
  • Better handling of direct (native)ByteBuf更好的处理直接(本地)的ByteBuf
  • 一个ByteBuf 可以被一个ByteBufAllocator包含.
public interface ByteBufAllocator {

ByteBuf buffer();
ByteBuf buffer(int initialCapacity);
ByteBuf buffer(int initialCapacity, int maxCapacity);
ByteBuf heapBuffer();
ByteBuf heapBuffer(int initialCapacity);
ByteBuf heapBuffer(int initialCapacity, int maxCapacity);
ByteBuf directBuffer();
ByteBuf directBuffer(int initialCapacity);
ByteBuf directBuffer(int initialCapacity, int maxCapacity);
ByteBuf ioBuffer();

CompositeByteBuf compositeBuffer();
CompositeByteBuf compositeBuffer(int maxNumComponents);
CompositeByteBuf compositeHeapBuffer();
CompositeByteBuf compositeHeapBuffer(int maxNumComponents);
CompositeByteBuf compositeDirectBuffer();
CompositeByteBuf compositeDirectBuffer(int maxNumComponents);
}
要想从一个handler那里获取当前的 ByteBufAllocator,可以使用ChannelHandlerContext.alloc()或Channel.alloc()方法:
Channel channel = ...;
ByteBuf buf = channel.alloc().buffer(512);
....
channel.write(buf);

ChannelHandlerContext ctx = ...
ByteBuf buf2 = ctx.alloc().buffer(512);
....
channel.write(buf2)

一旦一个ByteBuf被写入远程节点,它会再次自动的释放进入释放到池(the pool)里。

默认的ByteBufAllocator为PooledByteBufAllocator.如果你不希望使用buffer pooling或使用你自己的allocator,你可以运用Channel.config ().setAllocator(..),以及一个可供选择的 allocator,比如UnpooledByteBufAllocator。

Channel API的变化

在4.0中,许多io.netty.channel包中的类都经历大量修改,因此文本上的简单搜索-替换是无法让你基于3.x的程序迁移到4.0上。这个部分会尝试将这些重大变更背后的思考过程展示出来 ,而不只是简单地作为展示所有变更。

翻新后的ChannelHandler接口

Upstream → Inbound, Downstream → Outbound

对于初学者来说,术语'upstream'(译者注:直
译为向上游,有点像TCP/IP协议栈中从下往上,从物理层最终到达应用层这么一个流程)和'downstream'有点让人迷惑。在4.0中,只要可
能,都会使
用'inbound'(译者注:直译为开往内地的,相对于upstream确实更贴切,即指数据从外部网络经历层层filter到达我们的处理逻辑)和
'outbound'来替换他们。

新的ChannelHandler继承层次

在3.x时代,ChannelHandler只是一个标记接口,而在ChannelUpstreamHandler、ChannelDownstreamHandler、LifeCycleAwareChannelHandler定义了具体的处理器方法。在 Netty 4中,ChannelHandler将LifeCycleAwareChannelHandler接口和一堆实现辅助方法融合到了一起,具体见代码:

public interface ChannelHandler {

void beforeAdd(ChannelHandlerContext ctx) throws Exception;
void afterAdd(ChannelHandlerContext ctx) throws Exception;
void beforeRemove(ChannelHandlerContext ctx) throws Exception;
void afterRemove(ChannelHandlerContext ctx) throws Exception;

void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;
...
}

下方的图表描述了这个新的类型集成层次:

fixme(原文中还没有插入此图)

事件对象从ChannelHandler中消失了

在3.x时代,所有的I/O操作都会创建一个新的
ChannelEvent对象。对每个读或写的操作,还会额外创建一个新的ChannelBuffer对象。由于将资源管理和buffer的池化交给了
JVM,这实际上极大地简化了 Netty的内部实现。但是,基于Netty开发的应用在高负载下运行时,有时会观察到GC(Garbage
Collection)的压力增大或变化不定,这些问题的根源也来自于这里。

4.0通过把事件对象替换为直接与类型相对应(译者注:原文为strongly typed,但是我觉得直译为强类型不太容易理解)的方法调用,几乎完全避免了事件对象的创建。3.x中,有类似于 handleUpstream()和handleDownstream()这种能够捕获所有相关类型事件的处理器方法,4.0中你将不会再看到它们的身影了。所有的事件类型现在都有各自对应的处理器方法:

// 3.x时代: void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception; void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception; // 4.0: void channelRegistered(ChannelHandlerContext ctx) throws Exception; void channelUnregistered(ChannelHandlerContext ctx) throws Exception; void channelActive(ChannelHandlerContext ctx) throws Exception; void channelInactive(ChannelHandlerContext ctx) throws Exception; void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception; void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelFuture future) throws Exception; void connect( ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelFuture future) throws Exception; void disconnect(ChannelHandlerContext ctx, ChannelFuture future) throws Exception; void close(ChannelHandlerContext ctx, ChannelFuture future) throws Exception; void deregister(ChannelHandlerContext ctx, ChannelFuture future) throws Exception; void flush(ChannelHandlerContext ctx, ChannelFuture future) throws Exception; void read(ChannelHandlerContext ctx); void sendFile(ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception;

ChannelHandlerContext类也被修改来反映上述提到的变化:

 

// Before:
ctx.sendUpstream(evt);

// After:
ctx.fireInboundBufferUpdated();

所有这些变化意味着用户无法去扩展ChannelEvent这个已经不存在的接口了。那用户要怎样才能定义他或她自己的事件类型呢,就像IdleStateEvent?4.0中的ChannelHandler有一个处理器方法叫做 userEventTriggered(),它就是被设计用来满足这种特殊的用户需求。

Simplified channel state model

在3.x中,当一个新的Channel被创建并连接成功,至少三个ChannelStateEvent会被触发:channelOpen、channelBound以及channelConnected。当一个Channel关闭,则对应channelDisconnected 、channelUnbound以及channelClosed三个事件。

fixme

但是,触发这么多事件的意义并不那么明显。如果在一个Channel进入可读或可写的状态时通知用户,想来会更有帮助。

fixme

channelOpen、channelBoundchannelConnected被合并为channelActive。channelDisconnected、channelUnboundchannelClosed被合并为channelInactive。类似的,Channel.isBound()和Channel.isConnected()也被合并为了 Channel.isActive()。

需要注意的是,channelRegistered和channelUnregistered这两个事件与channelOpen和channelClosed具有的意义是不一样的。它们 (channelRegistered和channelUnregistered)是在支持Channel的动态注册、注销以及再注册时被引入的,就像下图所示:

fixme


酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部