[TOC]
ChannelHandler
简介
- netty允许自定义ChannelHandler的实现来处理数据。ChannelPipeline是ChannelHandler实例的列表,用于处理或截获通道的接收和发送数据。ChannelPipeline提供了一种高级的截取过滤器模式,让用户可以在ChannelPipeline中完全控制一个事件及如何处理ChannelHandler与ChannelPipeline的交互
- 对于每个新的通道,会创建一个新的ChannelPipeline并附加至通道。一旦连接,Channel和ChannelPipeline的耦合性是永久的,Channel不能附加其他的ChannelPipeline或从ChannelPipeline分离. 每个Channel都有一个属于自己的Pipeline,调用Channel#pipeline()方法可以获得Channel的Pipeline,调用Pipeline#channel()方法可以获得Pipeline的Channel。
- 对于每个新的通道,会创建一个新的ChannelPipeline并附加至通道。一旦连接,Channel和ChannelPipeline的耦合性是永久的,Channel不能附加其他的ChannelPipeline或从ChannelPipeline分离. 每个Channel都有一个属于自己的Pipeline,调用Channel#pipeline()方法可以获得Channel的Pipeline,调用Pipeline#channel()方法可以获得Pipeline的Channel。
很明显,ChannelPipeline里面就是一个ChannelHandler的列表。如果一个入站IO事件被触发,这个事件会从第一个开始依次通过ChannelPipeline中的ChannelHandler。若是一个入站I/O事件,则会从最后一个开始依次通过ChannelPipeline中的ChannelHandler。ChannelHandler可以处理事件并检查类型,如果某个ChannelHandler不能处理则会跳过,并将事件传递到下一个ChannelHandler。ChannelPipeline可以动态添加、删除、替换其中的ChannelHandler,这样的机制可以提高灵活性。
修改ChannelPipeline addFirst(...),添加ChannelHandler在ChannelPipeline的第一个位置 addBefore(...),在ChannelPipeline中指定的ChannelHandler名称之前添加ChannelHandler addAfter(...),在ChannelPipeline中指定的ChannelHandler名称之后添加ChannelHandler addLast(ChannelHandler...),在ChannelPipeline的末尾添加ChannelHandler remove(...),删除ChannelPipeline中指定的ChannelHandler replace(...),替换ChannelPipeline中指定的ChannelHandler
被添加到ChannelPipeline的ChannelHandler将通过IO-Thread处理事件,这意味了必须不能有其他的IO-Thread阻塞来影响IO的整体处理;有时候可能需要阻塞,例如JDBC。因此netty允许通过一个EventExecutorGroup到每一个ChannelPipeline.add*方法,自定义的事件会被包含在EventExecutorGroup中的EventExecutor来处理,默认的实现是DefaultEventExecutorGroup。
ChannelHandlerContext 每个ChannelHandler被添加到ChannelPipeline后,都会创建一个ChannelHandlerContext并与之创建的ChannelHandler关联绑定。ChannelHandlerContext允许ChannelHandler与其他的ChannelHandler实现进行交互,这是相同ChannelPipeline的一部分。ChannelHandlerContext不会改变添加到其中的ChannelHandler,因此它是安全的 下图显示了ChannelHandlerContext、ChannelHandler、ChannelPipeline的关系
调用ChannelHandlerContext#channel()方法可以得到和Context绑定的Channel,调用ChannelHandlerContext#handler()方法可以得到和Context绑定的Handler。
Netty中发送消息有两种方法: 1、直接写入通道导致处理消息从ChannelPipeline的尾部开始 2、写入ChannelHandlerContext对象导致处理消息从ChannelPipeline的下一个handler开始
这两个方法都可以让事件流全部通过ChannelPipeline。无论从头部还是尾部开始,因为它主要依赖于事件的性质。如果是一个“入站”事件,它开始于头部;若是一个“出站”事件,则开始于尾部。
- Channel的生命周期
状态 | 描述 |
---|---|
ChannelUnregistered | Channel已创建,还未注册到一个EventLoop上 |
ChannelRegistered | Channel已经注册到一个EventLoop上 |
ChannelActive | Channel是活跃状态(连接到某个远端),可以收发数据 |
ChannelInactive | Channel未连接到远端 |
- ChannelInboundHandler ChannelInboundHandler提供了一些方法再接收数据或Channel状态改变时被调用。下面是ChannelInboundHandler的一些方法: channelRegistered,ChannelHandlerContext的Channel被注册到EventLoop; channelUnregistered,ChannelHandlerContext的Channel从EventLoop中注销 channelActive,ChannelHandlerContext的Channel已激活 channelInactive,ChannelHanderContxt的Channel结束生命周期 channelRead,从当前Channel的对端读取消息 channelReadComplete,消息读取完成后执行 userEventTriggered,一个用户事件被处罚 channelWritabilityChanged,改变通道的可写状态,可以使用Channel.isWritable()检查 exceptionCaught,重写父类ChannelHandler的方法,处理异常
常规的运行顺序 //连接成功 handlerAdded() channelActive() //客户端发送数据过来 channelRead() channelReadComplete() //连接失效 channelInactive() channelUnregistered handlerRemoved()
ChannelInboundHandlerAdapter的channelRead方法处理完消息后不会自动释放消息,若想自动释放收到的消息,可以使用SimpleChannelInboundHandler或者手动释放ReferenceCountUtil.release(msg);因为SimpleChannelInboundHandler自动释放资源,任何对消息的引用都会变成无效,所以你不能保存这些引用待后来使用.