Redission 队列底层实现原理详解

关键两个类:

CommandPubSubDecoder.java

// Netty 读取到数据后,发送给 redission  
protected void decodeCommand(Channel channel, ByteBuf in, QueueCommand data, int endIndex) throws Exception {
        try {
            while (in.writerIndex() > in.readerIndex()) {
                if (data != null) {
                    if (((CommandData<Object, Object>) data).getPromise().isDone()) {
                        data = null;
                    }
                }
                decode(in, (CommandData<Object, Object>) data, null, channel, false, null, 0);
            }
            sendNext(channel, data);//数据读取完成后,调用 消息发送
        } catch (Exception e) {
            log.error("Unable to decode data. channel: {}, reply: {}", channel, LogHelper.toString(in), e);
            if (data != null) {
                data.tryFailure(e);
            }
            sendNext(channel);
            throw e;
        }
    }

CommandDecoder .java

调用父类进行协议解析

    @Override
    protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        QueueCommandHolder holder = getCommand(ctx);
        QueueCommand data = null;
        if (holder != null) {
            data = holder.getCommand();
        }

        if (state() == null) {
            state(new State());
        }
        
        if (data == null) {
            while (in.writerIndex() > in.readerIndex()) {
                int endIndex = skipCommand(in);

                try {
                    decode(ctx, in, null, 0);
                } catch (Exception e) {
                    in.readerIndex(endIndex);
                    throw e;
                }
            }
        } else {
            if (holder.getChannelPromise().isDone() && !holder.getChannelPromise().isSuccess()) {
                sendNext(ctx.channel());
                // throw REPLAY error
                in.indexOf(Integer.MAX_VALUE/2, Integer.MAX_VALUE, (byte) 0);
                return;
            }

            int endIndex = 0;
            if (!(data instanceof CommandsData)) {
                endIndex = skipCommand(in);
            } else {
                endIndex = skipBatchCommand(in, (CommandsData) data);
            }
            if (data.isExecuted()) {
                in.readerIndex(endIndex);
                sendNext(ctx.channel());
                return;
            }

            decode(ctx, in, data, endIndex);
        }
    }

具体如何解决:

    protected void skipDecode(ByteBuf in) throws IOException{
        int code = in.readByte();
        if (code == '_') {
            in.skipBytes(2);
        } else if (code == ',') {
            skipString(in);
        } else if (code == '+') {
            skipString(in);
        } else if (code == '-') {
            skipString(in);
        } else if (code == ':') {
            skipString(in);
        } else if (code == '$') {
            skipBytes(in);
        } else if (code == '=') {
            skipBytes(in);
        } else if (code == '%') {
            long size = readLong(in);
            for (int i = 0; i < size * 2; i++) {
                skipDecode(in);
            }
        } else if (code == '*' || code == '>' || code == '~') {
            long size = readLong(in);
            for (int i = 0; i < size; i++) {
                skipDecode(in);
            }
        }
    }

在解析完成后调用 对应的订阅服务:这里采用观察者模式:

CommandPubSubDecoder.java

 protected void decodeResult(CommandData<Object, Object> data, List<Object> parts, Channel channel,
            Object result) throws IOException {
        try {
            if (config.getExecutor().isShutdown()) {
                return;
            }
        } catch (IllegalStateException e) {
            // arise in JBOSS. skipped 
        }

        if (result instanceof Message) {
            checkpoint();

            RedisPubSubConnection pubSubConnection = RedisPubSubConnection.getFrom(channel);
            ChannelName channelName = ((Message) result).getChannel();
            if (result instanceof PubSubStatusMessage) {
                String operation = ((PubSubStatusMessage) result).getType().name().toLowerCase();
                PubSubKey key = new PubSubKey(channelName, operation);
                CommandData<Object, Object> d = commands.get(key);
                if (SUBSCRIBE_COMMANDS.contains(d.getCommand().getName())) {
                    commands.remove(key);
                    entries.put(channelName, new PubSubEntry(d.getMessageDecoder()));
                }
                
                if (UNSUBSCRIBE_COMMANDS.contains(d.getCommand().getName())) {
                    commands.remove(key);
                    if (result instanceof PubSubPatternMessage) {
                        channelName = ((PubSubPatternMessage) result).getPattern();
                    }
                    PubSubEntry entry = entries.remove(channelName);
                    if (config.isKeepPubSubOrder()) {
                        enqueueMessage(result, pubSubConnection, entry);
                    }
                }
            }

            if (config.isKeepPubSubOrder()) {
                if (result instanceof PubSubPatternMessage) {
                    channelName = ((PubSubPatternMessage) result).getPattern();
                }
                PubSubEntry entry = entries.get(channelName);
                if (entry != null) {
                    enqueueMessage(result, pubSubConnection, entry);
                }
            } else {
                config.getExecutor().execute(new Runnable() {
                    @Override
                    public void run() {
                        if (result instanceof PubSubStatusMessage) {
                            pubSubConnection.onMessage((PubSubStatusMessage) result);
                        } else if (result instanceof PubSubMessage) {
                            pubSubConnection.onMessage((PubSubMessage) result); //调用具体的订阅者
                        } else if (result instanceof PubSubPatternMessage) {
                            pubSubConnection.onMessage((PubSubPatternMessage) result);
                        }
                    }
                });
            }
        } else {
            super.decodeResult(data, parts, channel, result);
        }
    }

RedisPubSubConnection.java

通知所有监听者接收消息

public void onMessage(PubSubMessage message) {
        for (RedisPubSubListener<Object> redisPubSubListener : listeners) {
            redisPubSubListener.onMessage(message.getChannel(), message.getValue());
        }
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

树懒_Zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值