浅析RocketMQ-NameServer处理器

之前的文章,介绍了NameServer的启动流程,本篇分析下涉及到的几个Netty的处理器。

一. NettyEncoder

NettyEncoder继承自MessageToByteEncoder。
MessageToByteEncoder是Netty提供的基类,用于将返回的对象,转为字节流的处理器

public class NettyEncoder extends MessageToByteEncoder<RemotingCommand> {

    public void encode(ChannelHandlerContext ctx, RemotingCommand remotingCommand, ByteBuf out) {
			// 将数据头写出
            ByteBuffer header = remotingCommand.encodeHeader();
            out.writeBytes(header);
            // 将数据体写出
            byte[] body = remotingCommand.getBody();
            if (body != null) {
                out.writeBytes(body);
            }
        
    }
}

主要看下encodeHeader方法,

public ByteBuffer encodeHeader(final int bodyLength) {
        // header长度
        int length = 4;

        // header data 长度
        byte[] headerData;
        // 默认将当前对象,采用FastJSON转为字节数组
        headerData = this.headerEncode();

        length += headerData.length;

        // body 的长度
        length += bodyLength;
 
        ByteBuffer result = ByteBuffer.allocate(4 + length - bodyLength);

        // length
        result.putInt(length);

        // 这里对应ByteBuffer.allocate中的4,markProtocolType方法返回长度4个字节的数组
        // 低24存放headerData的长度,高位存放序列化方式
        result.put(markProtocolType(headerData.length, serializeTypeCurrentRPC));

        // header data
        result.put(headerData);

        result.flip();

        return result;
    }

最终序列化值得数据格式:
在这里插入图片描述

二. NettyDecoder

NettyDecoder 用于将字节流反序列化为自定义的对象。
注意默认构造里面的参数

  • 第一个0表示数据流长度偏移量,第二个4表示数据流长度,含义是数据流从0开始读取4个字节获取整个完整流要读取的长度。对应上文中设置result.putInt(length)的操作。
  • 第三个0表示读取数据流,是否继续偏移一定长度读取,这边不偏移读取
  • 第四个4表示忽略多少开始长度读取流数据。这里跳过4个字节,实际上吧length数据过滤。
public class NettyDecoder extends LengthFieldBasedFrameDecoder {
  
    private static final int FRAME_MAX_LENGTH =
        Integer.parseInt(System.getProperty("com.rocketmq.remoting.frameMaxLength", "16777216"));

    public NettyDecoder() {
        super(FRAME_MAX_LENGTH, 0, 4, 0, 4);
    }

    @Override
    public Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        	ByteBuf frame = null;
         	frame = (ByteBuf) super.decode(ctx, in);
            if (null == frame) {
                return null;
            }
            ByteBuffer byteBuffer = frame.nioBuffer();
            return RemotingCommand.decode(byteBuffer);
    }
}

按照构造中的定义,调用完super.decode(ctx, in)方法之后的,数据格式如下:
在这里插入图片描述

    public static RemotingCommand decode(final ByteBuffer byteBuffer) throws RemotingCommandException {
    	// 总的数据长度
        int length = byteBuffer.limit();
        // 获取到byte[]的数据
        int oriHeaderLen = byteBuffer.getInt();
        // 获取headerdata长度
        int headerLength = getHeaderLength(oriHeaderLen);
		
        byte[] headerData = new byte[headerLength];
        byteBuffer.get(headerData);

        RemotingCommand cmd = headerDecode(headerData, getProtocolType(oriHeaderLen));
		// 总长度-byte[]-header长度
        int bodyLength = length - 4 - headerLength;
        byte[] bodyData = null;
        if (bodyLength > 0) {
            bodyData = new byte[bodyLength];
            byteBuffer.get(bodyData);
        }
        cmd.body = bodyData;

        return cmd;
    }

三. NettyServerHandler

NettyServerHandler 是最后一步,将对应请求分配到实际业务去处理。

public void processMessageReceived(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
        final RemotingCommand cmd = msg;
        if (cmd != null) {
            switch (cmd.getType()) {
            	// 处理请求
                case REQUEST_COMMAND:
                    processRequestCommand(ctx, cmd);
                    break;
                // 处理响应    
                case RESPONSE_COMMAND:
                    processResponseCommand(ctx, cmd);
                    break;
                default:
                    break;
            }
        }
    }
  • 处理请求数据
    public void processRequestCommand(final ChannelHandlerContext ctx, final RemotingCommand cmd) {
    	// 根据具体的请求code,查询对应的处理策略,不存在使用默认策略(DefaultRequestProcessor)
        final Pair<NettyRequestProcessor, ExecutorService> matched = this.processorTable.get(cmd.getCode());
        final Pair<NettyRequestProcessor, ExecutorService> pair = null == matched ? this.defaultRequestProcessor : matched;
        // 请求序号
        final int opaque = cmd.getOpaque();

            Runnable run = new Runnable() {
                @Override
                public void run() {
                    
                        String remoteAddr = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
                        // 类似切面的调用前处理
                        doBeforeRpcHooks(remoteAddr, cmd);
                        final RemotingResponseCallback callback = new RemotingResponseCallback() {
                            @Override
                            public void callback(RemotingCommand response) {
                            	// 类似切面的调用后处理
                                doAfterRpcHooks(remoteAddr, cmd, response);
                                // 有返回的,把数据写回去
                                if (!cmd.isOnewayRPC()) {
                                    if (response != null) {
                                        response.setOpaque(opaque);
                                        response.markResponseType();
                                        ctx.writeAndFlush(response);
                                        }
                                    } 
                                }
                            }
                        };
                        // 如果是异步处理的,在回调中调用结果
                        if (pair.getObject1() instanceof AsyncNettyRequestProcessor) {
                            AsyncNettyRequestProcessor processor = (AsyncNettyRequestProcessor)pair.getObject1();
                            processor.asyncProcessRequest(ctx, cmd, callback);
                        } else {
                        	// 同步处理,直接等待处理结果
                            NettyRequestProcessor processor = pair.getObject1();
                            RemotingCommand response = processor.processRequest(ctx, cmd);
                            callback.callback(response);
                        }
                }
            };
			// ....省略不重要的
			// 提交任务执行
           final RequestTask requestTask = new RequestTask(run, ctx.channel(), cmd);
                pair.getObject2().submit(requestTask);
        
    }
  • 处理响应数据
    public void processResponseCommand(ChannelHandlerContext ctx, RemotingCommand cmd) {
     	// 请求序号
        final int opaque = cmd.getOpaque();
        // 获取对应的返回结果
        final ResponseFuture responseFuture = responseTable.get(opaque);
            responseFuture.setResponseCommand(cmd);

            responseTable.remove(opaque);
			// 异步的回调获取结果
            if (responseFuture.getInvokeCallback() != null) {
                executeInvokeCallback(responseFuture);
            } else {
            	// 同步直接设置结果
                responseFuture.putResponse(cmd);
                responseFuture.release();
            }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值