关键两个类:
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());
}
}