《Netty in Action》chapter 6 : ChannelHandler and ChannelPipeline
来源:互联网 发布:win2008端口转发 编辑:程序博客网 时间:2024/05/16 09:24
6.1 The ChannelHandler family
6.1.1 The Channel lifecycle
Channel lifecycle states
6.1.2 The ChannelHandler lifecycle
ChannelHandler lifecycle methods
6.1.3 Interface ChannelInboundHandler
ChannelInboundHandler负责明确地释放ByteBuf实例池相关的内存。可以是用netty提供的ReferenceCountUtil.release()
例如:
@Sharablepublic class DiscardHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ReferenceCountUtil.release(msg); }}
SimpleChannelInboundHandler
会自动调用ReferenceCountUtil.release(msg)
,故不用再去手动释放资源。
6.1.4 Interface ChannelOutboundHandler
6.1.5 ChannelHandler adapters
ChannelInboundHandlerAdapter
,ChannelOutboundHandlerAdapter
针对ChannelInboundHandler
和ChannelOutboundHandler
各自简单的实现,可以直接调用并override自己感兴趣的方法。
6.1.6 Resource management
当调用ChannelInboundHandler.channelRead()
,ChannelOutboundHandler.write()
可能会有内存泄漏,可以使用netty自带的 Class ResourceLeakDetector
来进行内存泄露检查。检查级别如下:
使用方法: java -Dio.netty.leakDetectionLevel=ADVANCED
6.2 Interface ChannelPipeline
ChannelPipeline 是一系列的ChannelHandler。ChannelPipeline还提供了一下传播event穿过它自己的方法。
I/O线程是不允许被阻塞的,也就是不能在ChannelHandler中进行任何阻塞式的处理,但是对此我们也有相应的解决方法.就是在把ChannelHanders添加到ChannelPipeline的时候,指定一个EventExecutorGroup,ChannelHandler中所有的方法都将会在这个指定的EventExecutorGroup中运行。而这个EVentExecutorGroup运行的线程与I/O线程不同,达到不阻塞I/O的目的。
Table 6.10 The ChannelHandlerContext API
Method name Description bind Binds to the given SocketAddress and returns a ChannelFuture channel Returns the Channel that is bound to this instance close Closes the Channel and returns a ChannelFuture connect Connects to the given SocketAddress and returns a ChannelFuture deregister Deregisters from the previously assigned EventExecutor and returns a ChannelFuture disconnect Disconnects from the remote peer and returns a ChannelFuture executor Returns the EventExecutor that dispatches events fireChannelActive Triggers a call to channelActive() (connected) on the nextChannelInboundHandler fireChannelInactive Triggers a call to channelInactive() (closed) on the next ChannelInboundHandler fireChannelRead Triggers a call to channelRead() (message received) on the next ChannelInboundHandler fireChannelReadComplete Triggers a channelWritabilityChanged event to the next ChannelInboundHandler handler Returns the ChannelHandler bound to this instance isRemoved Returns true if the associated ChannelHandler was removed from the ChannelPipeline name Returns the unique name of this instance pipeline Returns the associated ChannelPipeline read Reads data from the Channel into the first inbound buffer; triggers a channelRead event if successful and notifies the handler of channelReadComplete write Writes a message via this instance through the pipeline
6.3.1 Using ChannelHandlerContext
Listing 6.6 Accessing the Channel from a ChannelHandlerContext
ChannelHandlerContext ctx = ..;Channel channel = ctx.channel();channel.write(Unpooled.copiedBuffer("Netty in Action",CharsetUtil.UTF_8));
Listing 6.7 Accessing the ChannelPipeline from a ChannelHandlerContext
ChannelHandlerContext ctx = ..;ChannelPipeline pipeline = ctx.pipeline();pipeline.write(Unpooled.copiedBuffer("Netty in Action",CharsetUtil.UTF_8));
6.6和6.7是完全等效的。另外,write相当于一个event,从它被添加到ChannelHandlerContext时起,会遍历pipeline从头到尾的所有环节。
应该从ChannelPipeline中某个合适的点加入event,原因如下:
为了减少even在pipeline中对该event不该兴趣的ChannelHandler中传输的开销;
为了避免对该event感兴趣的ChannelHandler对该event进行处理。
如下面的例子:
Listing 6.8 Calling ChannelHandlerContext write()
ChannelHandlerContext ctx = ..;ctx.write(Unpooled.copiedBuffer("Netty in Action", CharsetUtil.UTF_8));
这个例子中,event是从下一个ChannelHandler进行处理,而不是从头到尾。
6.3.2 Advanced uses of ChannlHandler and ChannelHandlerContext
高级用法之一,从ChannlHandler中通过ChannelHandlerContext获取pipeline,然后动态地往pipeline中添加ChannlHander以完成各种复杂的需求,比如通过网pipeline中添加ChannlHandler支持动态协议变化。
高级用法之二,在ChannelHandler中缓存ChannelHandlerContext以供后用。而且可以在不同线程中执行。
Listing 6.9 Caching a ChannelHandlerContext
public class WriteHandler extends ChannelHandlerAdapter { private ChannelHandlerContext ctx; @Override public void handlerAdded(ChannelHandlerContext ctx) { this.ctx = ctx; } public void send(String msg) { ctx.writeAndFlush(msg); }}
由于一个ChannelHandler可以绑定到不同的ChannelPipeline,所以它可以绑定不同的ChannelHandlerContext实例。这种情况,必须注解为@Shareable
,否则会报异常。而且此时ChannelHandler必须为线程安全的。
Listing 6.10 A sharable ChannelHandler
@Sharablepublic class SharableHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) { //Log method calls and forwards to next ChannelHandler System.out.println("Channel read message: " + msg); ctx.fireChannelRead(msg); }}
Listing 6.11 Invalid usage of @Sharable
@Sharablepublic class UnsharableHandler extends ChannelInboundHandlerAdapter { private int count; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { //有自己的状态,非线程安全(可是使用synchronized解决) count++; System.out.println("channelRead(...) called the " + count + " time"); ctx.fireChannelRead(msg(); }}
注:这种方式可以用于统计多个pipeline中消息数量。
6.4 Exception handling
6.4.1 Handling inbound exceptions
Listing 6.12 Basic inbound exception handling
public class InboundExceptionHandler extends ChannelInboundHandlerAdapter {@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); }}
总结:
1. ChannelHandler.exceptionCaught()默认实现是将当前的异常传到pipeline中的下一个;
2. 如果到pipeline的最后没有处理,netty会打异常未处理日志;
3. 如果要自己处理异常,可以override exceptionCaught()
。
6.4.2 Handling outbound exceptions
两种方式:
Listing 6.13 Adding a ChannelFutureListener to a ChannelFuture
ChannelFuture future = channel.write(someMessage);future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture f) { if (!f.isSuccess()) { f.cause().printStackTrace(); f.channel().close(); } }});
Listing 6.14 Adding a ChannelFutureListener to a ChannelPromise
public class OutboundExceptionHandler extends ChannelOutboundHandlerAdapter { @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { promise.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture f) { if (!f.isSuccess()) { f.cause().printStackTrace(); f.channel().close(); } } }); }}
- 《Netty in Action》chapter 6 : ChannelHandler and ChannelPipeline
- Netty in action—ChannelHandler和ChannelPipeline
- 《Netty in Action》中文版—第六章 ChannelHandler和ChannelPipeline
- 6 ChannelHandler and ChannelPipeline
- Netty in Action (十五) 第六章节 第一部分 ChannelHandler和ChannelPipeline
- Netty 之 ChannelHandler,ChannelHandlerContext,ChannelPipeline
- Netty In Action 读书笔记 - 第六章 ChannelHandler
- Netty In Action中文版 - 第六章:ChannelHandler
- Netty In Action中文版 - 第六章:ChannelHandler
- netty in action第六章-ChannelHandler
- Netty实战读书笔记二:ChannelHandler和ChannelPipeline
- Netty(二)ChannelPipeline和ChannelHandler
- Netty学习笔记(三) ChannelPipeline和ChannelHandler
- netty in action第八章-附带的ChannelHandler和Codec
- 一起学Netty(四)之 ChannelHandler,ChannelHandlerContext,ChannelPipeline
- 一起学Netty(四)之 ChannelHandler,ChannelHandlerContext,ChannelPipeline
- [netty核心类]--ChannelPipeline和ChannelHandler源码分析
- 一起学Netty(四)之 ChannelHandler,ChannelHandlerContext,ChannelPipeline
- 通过TransactionDefinition接口来学习spring事务的隔离级别和传播特性(4.3.4版本)
- SpringBoot入门
- 简单介绍一些matlab常用的函数(1)
- Hyper-v虚拟机下Ubuntu Server 14.04 配置网络
- OkHttp
- 《Netty in Action》chapter 6 : ChannelHandler and ChannelPipeline
- #pragma预处理分析
- cf
- RxAndroid: 基础介绍(一)
- How tomcat works——序言
- var const let 三者之间的区别
- Swig在Mac OS X上的安装
- 淘淘商城系列——jsonp的原理及两种实现方式
- 解决