查看文档,它说:
https://netty.io/4.0/api/io/netty/channel/ChannelPipeline.html
用户应该在管道中拥有一个或多个ChannelHandler 接收I / O事件(例如读取)并请求I / O操作(例如, 写和关闭)。例如,典型的服务器将具有 在每个渠道的管道中跟随处理程序,但您的里程可能 取决于协议的复杂性和特征 和业务逻辑:
协议解码器 - 将二进制数据(例如ByteBuf)转换为Java 宾语。 协议编码器 - 将Java对象转换为二进制数据。
业务逻辑处理程序 - 执行实际的业务逻辑(例如 数据库访问)。它可以表示如下所示 以下示例:static final EventExecutorGroup group = new DefaultEventExecutorGroup(16); ...
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(" decoder",new MyProtocolDecoder());
pipeline.addLast(" encoder",new MyProtocolEncoder());
//告诉管道运行MyBusinessLogicHandler的事件处理程序 方法//在与I / O线程不同的线程中进行I / O. 某个耗时的任务不会阻止线程。 // 如果你的 业务逻辑完全异步或很快完成,你 不要//指定一个组。
pipeline.addLast(group," handler", 新的MyBusinessLogicHandler());
在Github上的很多例子中,我看到了同样的模式。我想知道是否有人可以解释为什么businessHandler不在解码器和编码器之间。我认为你会获得你的POJO,然后在业务处理程序中对它进行处理,然后对其进行编码。
答案 0 :(得分:2)
由于调用处理程序的顺序,解码器和编码器通常位于管道的开头。对于传入的数据,它是自下而上的,也是自上而下的传出。
E.g。
pipeline.addLast(new MyEncoder());
pipeline.addLast(new MyDecoder());
pipeline.addLast(new MyBusiness());
在这种情况下,对于传入数据,呼叫顺序是:MyDecoder(将数据转换为POJO) - > MyBusiness(不为传入流调用编码器)和传出数据:MyBusiness - > MyEncoder(没有为传出流调用解码器)。
如果您在业务处理程序中接收到传入流(实际上,解码器之后的POJO)对其进行处理并将其写回,则看起来MyBusiness位于编码器和解码器之间,因为数据正在返回编码器。
答案 1 :(得分:1)
当然,业务处理程序位于解码器和编码器之间。以Factorial示例为例。
public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
}
// Enable stream compression (you can remove these two if unnecessary)
pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
// Add the number codec first,
pipeline.addLast(new BigIntegerDecoder());
pipeline.addLast(new NumberEncoder());
// and then business logic.
// Please note we create a handler for every new channel
// because it has stateful properties.
pipeline.addLast(new FactorialServerHandler());
}`
在initChannel
函数中认为管道首先添加编码器和解码器,最后添加处理程序。执行流程实际上由解码器,处理程序和编码器排序。
解码器,处理程序和编码器等处理程序实际存储在AbstractChannelHandlerContext
类中。这是netty中AbstractChannelHandlerContext
的链接列表。列表的排列方式如decoder context
- > handler context
- > encoder context
,执行方式相同!
答案 2 :(得分:0)
实际上,如果在服务器中添加1.解码器,2。businessHandler,3。编码器,然后编写ctx.channel().writeAndFlush()
或ctx.pipeline().writeAndFlush()
,则将调用编码器。在这种情况下是bc,它将从尾部开始查找上一个outboundChannel。但是,如果您编写ctx.writeAndFlush()
,它将从businessHandler的位置查找prev outboundChannel。
在AbstractChannelHandlerContext的findContextOutbound()
的第一行中添加一个断点,即可得到它。
private AbstractChannelHandlerContext findContextOutbound(int mask) {
AbstractChannelHandlerContext ctx = this;
EventExecutor currentExecutor = executor();
do {
ctx = ctx.prev;
} while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_OUTBOUND));
return ctx;
}