ChannelHandler继承体系

ChannelHandler:所有逻辑处理器的抽象。
public interface ChannelHandler {
// handler添加完成回调
void handlerAdded(ChannelHandlerContext ctx) throws Exception;
// handler删除完成回调
void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
// 异常回调
@Deprecated
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
// 指定handler为共享handler,可重复添加到pipeline
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Sharable {
// no value
}
}
ChannelInboundHandler:基于ChannelHandler,扩展了一些Inbound事件。
public interface ChannelInboundHandler extends ChannelHandler {
// channel注册回调,当channel注册到NioEventLoop对应的Selector是触发该回调
void channelRegistered(ChannelHandlerContext ctx) throws Exception;
// channel注销回调
void channelUnregistered(ChannelHandlerContext ctx) throws Exception;
// channel激活回调
void channelActive(ChannelHandlerContext ctx) throws Exception;
// channel失效回调
void channelInactive(ChannelHandlerContext ctx) throws Exception;
// 读到数据时执行该方法
void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;
// 数据读完的回调
void channelReadComplete(ChannelHandlerContext ctx) throws Exception;
// 用户自定义的触发事件
void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;
// 改变channel的可写状态
void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception;
// 异常捕获
@Override
@SuppressWarnings("deprecation")
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}
事件传播过程
定义三个自定义的InBoundHandler类:
InBoundHandlerA
public class InBoundHandlerA extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("InBoundHandlerA: " + msg);
ctx.fireChannelRead(msg);
}
}
InBoundHandlerB
public class InBoundHandlerB extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("InBoundHandlerB: " + msg);
ctx.fireChannelRead(msg);
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("InBoundHandlerB: channelActive");
ctx.channel().pipeline().fireChannelRead("hello world");
}
}
InBoundHandlerC
public class InBoundHandlerC extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("InBoundHandlerC: " + msg);
ctx.fireChannelRead(msg);
}
}
在启动类中添加这三个handler
public static void main(String[] args) throws Exception {
// 配置服务端的 NIO线程组
// boss线程组用于网络事件的监听
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// worker线程组用于SocketChannel的网络读写
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// NIO服务端的辅助启动类,目的是降低服务端开发的复杂度
ServerBootstrap b = new ServerBootstrap();
// 配置两大线程组
b.group(bossGroup, workerGroup)
// 配置服务端channel,在服务启动时通过反射创建channel实例
.channel(NioServerSocketChannel.class)
// 配置TCP基本属性
.childOption(ChannelOption.TCP_NODELAY, true)
// 客户端创建连接时绑定基本属性
.childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue")
// 配置服务端启动过程逻辑处理器
.handler(new ServerHandler())
// 配置业务处理链 handler pipeline
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
// Inbound事件传播
ch.pipeline().addLast(new InBoundHandlerA());
ch.pipeline().addLast(new InBoundHandlerB());
ch.pipeline().addLast(new InBoundHandlerC());
}
});
// 前面都是一些属性配置的逻辑,真正的服务端启动在此处开始
// 绑定端口,正式启动server端服务
ChannelFuture f = b.bind(8888).sync();
// 同步等待,直至服务端监听端口关闭
f.channel().closeFuture().sync();
} finally {
// 优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
启动服务端,通过“telnet 127.0.0.1 8888”测试一下调用结果:

fireChannelRead方法源码
@Override
public final ChannelPipeline fireChannelRead(Object msg) {
AbstractChannelHandlerContext.invokeChannelRead(head, msg);
return this;
}
@Override
public ChannelHandlerContext fireChannelRead(final Object msg) {
// findContextInbound方法遍历链表,寻找下一个inbound节点,传播事件
invokeChannelRead(findContextInbound(), msg);
return this;
}
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRead(m);
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRead(m);
}
});
}
}
private void invokeChannelRead(Object msg) {
if (invokeHandler()) {
try {
// 调用channelRead方法
((ChannelInboundHandler) handler()).channelRead(this, msg);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelRead(msg);
}
}
执行过程总结:
因为InBoundHandlerB实现了channelActive方法,所以在channel被激活之后会首先调用该方法。
在channelActive方法中,是通过 “ctx.channel().pipeline().fireChannelRead("hello world");” 从head节点开始进行事件传播,传播顺序为:head->A->B->C->tail,与添加时的顺序是一样的。
而在channelRead方法中,是通过“ctx.fireChannelRead(msg);”从当前节点开始向下传播,直到tail。
fireChannelRead是从head节点或当前节点开始传播,先找到下一个inbound节点,然后再执行其channelRead方法,最后由tail节点做一些收尾工作并释放。
SimpleChannelInboundHandler
在上面了解到的事件传播机制中,资源的释放都是由tail节点完成的。如果由于某种原因,资源没有被传递到tail节点,这时就需要节点自己释放资源。
SimpleChannelInboundHandler提供了channelRead模板方法,封装了资源释放的逻辑。
当我们自定义的handler节点需要自己释放资源时,可以通过继承SimpleChannelInboundHandler重写channelRead0来实现。
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
boolean release = true;
try {
if (acceptInboundMessage(msg)) {
@SuppressWarnings("unchecked")
I imsg = (I) msg;
// 业务handler实现
channelRead0(ctx, imsg);
} else {
release = false;
ctx.fireChannelRead(msg);
}
} finally {
if (autoRelease && release) {
ReferenceCountUtil.release(msg);
}
}
}
protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception;
来源:CSDN
作者:KeepMoving++
链接:https://blog.csdn.net/u011212394/article/details/103950445