ChannelInboundInvoker接口
这个就是入站调用者的接口,也就是说有信息过来了,他可能会触发哪些事件:
具体的都是一些接受消息的事件方法,也就是被动的。
ChannelOutboundInvoker接口
有来的数据,当然有写出去的啦:
具体都是一些发送消息事件方法,基本都是主动的。
ChannelPipeline接口
而我们的管道也是继承上面的接口的,也就是一个主动的调用者:
也就是说所有的进出信息都需要经过管道,所有的处理事件也会经过管道。我们来看看管道自己定义了哪些接口,没截完整,有点长,但是可以看出来基本都是一些增删改查的操作,还有一些出站入站接口的覆盖:
所以可以看出来,管道就是个容器,管理着里面的处理器。
ChannelHandlerContext接口
通道处理器上下文接口,也是个主动的调用者,这个东西其实就是处理器的包装,处理器只要负责处理数据,至于数据是哪里来,又要往哪里去,处理器之间怎么通信,处理器怎么和管道交互,都由处理器上下文来管理,而且管道中其实存放的是处理器上下文,处理器是被包装在里面的,这个后面我们会看到,先来看看这个接口:
他也是实现了上面的出站入站接口,因为要相应管道的操作呀,他还实现了一个AttributeMap
接口,这个是给通道设置属性的,后面会讲到。来看看他的接口方法:
除了入站的操作外,还保存了通道,事件执行器,处理器,字节缓冲区分配器,管道,可见他就是跟这些交互的桥梁啊。
AbstractChannelHandlerContext抽象类
实现了ChannelHandlerContext
接口,和资源泄露提示的接口ResourceLeakHint
:
他基本已经把所有的处理器上下文接口都实现了,除了handler()
方法,内部还定义了HeadContext
和TailContext
两个上下文,作为基本处理器,具体后面会讲。他没实现handler()
方法,具体交给默认实现类实现。HeadContext
和TailContext
的处理器就是他们本身。
DefaultChannelHandlerContext
AbstractChannelHandlerContext
默认实现类,实现了handler()
方法,就是创建时候传进来的处理器。
final class DefaultChannelHandlerContext extends AbstractChannelHandlerContext {
//保存处理器
private final ChannelHandler handler;
DefaultChannelHandlerContext(
DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
super(pipeline, executor, name, handler.getClass());
this.handler = handler;//设置处理器
}
@Override
public ChannelHandler handler() {
return handler;
}
}
ChannelHandler接口
这个就是我们的处理器啦,他只是个原始接口,只有处理器的添加和删除事件:
ChannelInboundHandler接口
入站处理器接口,这个就是定义入站处理器要做哪些操作,其实和前面的ChannelInboundInvoker
是对应的,只是处理器是负责真正的处理,调用者负责触发某些事件:
ChannelOutboundHandler接口
出站处理器接口也类似:
ChannelHandlerAdapter抽象类
他是处理器实现的一个基本骨架,他实现的添加和删除方法都是空的,需要子类覆盖:
ChannelInboundHandlerAdapter实现类
我们常用的是这个,他继承了ChannelHandlerAdapter
,还实现了ChannelInboundHandler
接口,所以他就可以处理入站事件啦:
其实他的所有方法默认都是不触发的,因为有Skip
标注,这个我前面有讲过,处理器会匹配相应的处理方法,标注了就不会被匹配到了,也就跳过这个处理器了,也就是默认子类不覆盖方法就是不处理的:
我们可以看看ChannelInboundHandlerAdapter
源码:
public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {
@Skip
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelRegistered();
}
@Skip
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelUnregistered();
}
@Skip
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
}
@Skip
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelInactive();
}
@Skip
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.fireChannelRead(msg);
}
@Skip
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelReadComplete();
}
@Skip
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
ctx.fireUserEventTriggered(evt);
}
@Skip
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelWritabilityChanged();
}
@Skip
@Override
@SuppressWarnings("deprecation")
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
ctx.fireExceptionCaught(cause);
}
}
默认全是跳过的,其实里面的实现ctx.fireXX
也是继续传递给下一个处理器处理。
ChannelOutboundHandlerAdapter实现类
当然出站的也类似:
DefaultChannelPipeline数据的入站出站
首先他是ChannelPipeline
接口的实现类,拥有管理通道上下文的能力,同时又实现了出站入站调用者,也就是有能力可以触发那些事件:
我们先画个大致的图,看看他是怎么管理的:
如果有出入站事件来了,传播的路径可能是这样的,所有事件都传递下去了:
当然也可能某个处理器处理完了不传递数据了,比如入站事件入站处理器1
处理了,然后就完了,因为他没调用ctx.fireChannelRead(msg);
:
当然出如站处理器也可以这样,入站数据传递到入站处理器3
,然后直接在入站处理器3
这里进行写,然后出站数据传递到出站处理器2
里不再传递了,其实一般的写只是写在出站缓冲区中,还并没有写进通道里,这个具体后面会详细讲:
所以这个入站出站的顺序和操作非常灵活,只要搞明白原理,就觉得这个真的非常强大。今天只是先做个铺垫,没讲什么源码,下一篇就着重讲这个入站出站的过程和原理,还有里面的一些细节,这个也是很重要的,这样你才能设计出强大的处理器链条,才能用更少的处理器组合出强大的功能,才能再出问题的时候知道要怎么解决问题。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。