【Netty学习】 ChannelHandler 改动及影响
channelHandler 在Netty 4.x版本有了相当大的改动
http://netty.io/wiki/new-and-noteworthy.html 官网的更新改进说明。
以下节选官网更新说明的部分中文翻译:
“
在3.x时代,所有的I/O操作都会创建一个新的ChannelEvent对象。对每个读或写的操作,还会额外创建一个新的ChannelBuffer对象。由于将资源管理和buffer的池化交给了JVM,这实际上极大地简化了Netty的内部实现。但是,基于Netty开发的应用在高负载下运行时,有时会观察到GC(Garbage Collection)的压力增大或变化不定,这些问题的根源也来自于这里。
4.0通过把事件对象替换为直接与类型相对应(译者注:原文为strongly typed,但是我觉得直译为强类型不太容易理解)的方法调用,几乎完全避免了事件对象的创建。3.x中,有类似于handleUpstream()和handleDownstream()这种能够捕获所有相关类型事件的处理器方法,4.0中你将不会再看到它们的身影了。所有的事件类型现在都有各自对应的处理器方法:
“
”所有这些变化意味着用户无法去扩展ChannelEvent这个已经不存在的接口了。那用户要怎样才能定义他或她自己的事件类型呢,就像IdleStateEvent?4.0中的ChannelHandler有一个处理器方法叫做userEventTriggered(),它就是被设计用来满足这种特殊的用户需求。
“
4.x版本中简化了channel 状态模型(Simplified channel state model):
3.x版本的:
在4.x版本中:
ChannelOpen ChannelBound 和ChannelConnected 合并到ChannelActive.ChannelDisconnected ChannelUnbound ChannlClosed合并到ChannelInactive中
如下图所示:
在Netty4.0.12的源代码中我们可以看到AbstractChannel中的:
AbstractUnsafe{
...//调用fireChannelActive()
private void register0(ChannelPromise promise)
public final void bind(final SocketAddress localAddress, final ChannelPromise promise)
...//调用fireChannelInactive()
public final void disconnect(final ChannelPromise promise)
public final void close(final ChannelPromise promise)
}
..值得注意的是官网还特意提示了ChannelRegister和ChannelOpen和ChannelClosed有很大的区别
引入翻译:"channelRegistered和channelUnregistered这两个事件与channelOpen和channelClosed具有的意义是不一样的。它们(channelRegistered和channelUnregistered)是在支持Channel的动态注册、注销以及再注册时被引入的"
如图所示。注册和注销仅仅用于每次的操作。
以下是个人口水:
貌似这么做的好处在于。把channel的异常放在一个方法内统一处理。在3.x的开发过程中发现。很多时候我们想要的只是一个结果。服务端数据在客户端channel断开连接。解绑定。关闭3中状态时,需要将相对应的信息数据处理掉。在4.x版本中将这三个事件整合之后。只需要统一的处理就好了。
1 // 管道从不活跃状态 转到 活跃状态 触发 2 @Override 3 public void channelActive(ChannelHandlerContext ctx) throws Exception { 4 final Channel channel = ctx.channel(); 5 if(channel.isOpen()){ 6 // 管道 活跃的 并且是开启状态 7 } 8 super.channelActive(ctx); 9 } 10 11 // 管道从活跃状态 转到 不活跃状态 触发 12 @Override 13 public void channelInactive(ChannelHandlerContext ctx) throws Exception { 14 15 Channel channel = ctx.channel(); 16 if(!channel.isOpen()){ 17 18 19 } 20 super.channelInactive(ctx); 21 }