面试题答案
一键面试Reactor模式与ChannelHandler机制协同工作原理
- Reactor模式基础:
- Netty基于Reactor模式构建。Reactor模式中,有一个或多个Reactor线程负责监听网络事件(如连接建立、读、写事件等)。在Netty中,NioEventLoop就是Reactor线程的具体实现,它管理着一个Selector,用于监听各种网络事件。
- ChannelHandler机制:
- ChannelHandler是Netty处理业务逻辑的核心组件,分为入站处理器(InboundHandler)和出站处理器(OutboundHandler)。入站处理器处理从网络读取的数据,出站处理器处理要发送到网络的数据。
- 协同工作流程:
- 事件监听与分发:
- Reactor线程(NioEventLoop)通过Selector监听网络事件。当有事件发生时,例如有新连接接入(对应OP_ACCEPT事件),NioEventLoop会将该事件分发给对应的Channel。
- 每个Channel都关联着一个ChannelPipeline,ChannelPipeline持有一系列ChannelHandler。
- 入站处理流程:
- 以读事件为例,当有数据可读(OP_READ事件),NioEventLoop从对应的Channel读取数据后,会将数据封装成入站事件,然后从ChannelPipeline的头开始,依次传递给每个入站ChannelHandler进行处理。比如,假设ChannelPipeline中有一个自定义的MyInboundHandler,数据会先到达MyInboundHandler的
channelRead
方法,在这个方法中可以进行业务逻辑处理,如数据解码、业务逻辑计算等。
- 以读事件为例,当有数据可读(OP_READ事件),NioEventLoop从对应的Channel读取数据后,会将数据封装成入站事件,然后从ChannelPipeline的头开始,依次传递给每个入站ChannelHandler进行处理。比如,假设ChannelPipeline中有一个自定义的MyInboundHandler,数据会先到达MyInboundHandler的
- 出站处理流程:
- 当需要向网络发送数据时,例如调用
channel.writeAndFlush()
方法,数据会从ChannelPipeline的尾开始,依次经过每个出站ChannelHandler的处理,最后由最前面的出站Handler将数据写入到对应的Channel并发送出去。例如,假设有一个MyOutboundHandler,数据会先经过它的write
方法,在这里可以进行数据编码等操作。
- 当需要向网络发送数据时,例如调用
- 事件监听与分发:
举例说明
- 场景:实现一个简单的Netty服务器,接收客户端发送的字符串,将其转为大写后回显给客户端。
- 代码实现:
- 自定义入站处理器:
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class MyInboundHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
// 将接收到的字符串转为大写
String upperCaseMsg = msg.toUpperCase();
// 将处理后的消息写出
ctx.writeAndFlush(upperCaseMsg);
}
}
- 服务器启动代码:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class NettyServer {
public static void main(String[] args) {
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加自定义入站处理器
pipeline.addLast(new MyInboundHandler());
}
});
ChannelFuture f = b.bind(8888).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
- 交互流程分析:
- 入站阶段:
- Reactor线程(NioEventLoop)监听OP_READ事件,当客户端发送数据时,事件触发,NioEventLoop读取数据并封装成入站事件。
- 入站事件沿着ChannelPipeline传递,到达
MyInboundHandler
的channelRead0
方法,在这个方法中进行字符串转大写的业务逻辑处理。
- 出站阶段:
MyInboundHandler
处理完业务逻辑后,调用ctx.writeAndFlush(upperCaseMsg)
,数据从ChannelPipeline的尾开始,由于这里没有出站处理器,直接由最前面的出站Handler将数据写入Channel并发送给客户端。
- 入站阶段:
通过上述方式,Reactor模式负责高效的网络事件监听和分发,ChannelHandler机制负责具体业务逻辑的处理,二者协同工作完成复杂的网络业务逻辑处理。