io.lettuce.core.protocol.AsyncCommand 命令
io.lettuce.core.FutureSyncInvocationHandler 执行具体command命令的地方
io.lettuce.core.protocol.CommandHandler 向redis服务器发送指令/从redis服务器那儿接收指令
lettuce客户端通过io.lettuce.core.protocol.CommandHandler向redis服务器发送指令,并接收redis服务器返回的消息
底层是通过Netty和redis进行通信
io.lettuce.core.protocol.CommandHandler就是一个channelHandler,负责发送\接收消息,CommandHandler维护了一个stack(存放AsyncCommand的队列)。
当CommandHandler往redis服务器发送一个指令时会同时往stack入栈这个指令(AsyncCommand),当CommandHandler接收到redis服务器的消息时从stack出栈一个AsyncCommand,
根据接收到的消息内容设置AsyncCommand命令的结果。
io.lettuce.core.protocol.AsyncCommand是一个CompletableFuture,当应用向redis发送命令时,会将命令封装成AsyncCommand,然后等待执行结果,这个结果就是等待CommandHandler
在接收redis消息时解析内容并将结果返回给AsyncCommand。
发送指令
=====io.lettuce.core.FutureSyncInvocationHandler
@Override
protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
try {
Method targetMethod = this.translator.get(method);
Object result = targetMethod.invoke(asyncApi, args);
if (result instanceof RedisFuture<?>) {
RedisFuture<?> command = (RedisFuture<?>) result;
if (!isTxControlMethod(method.getName(), args) && isTransactionActive(connection)) {
return null;
}
long timeout = getTimeoutNs(command);
//等待指令执行结果
return Futures.awaitOrCancel(command, timeout, TimeUnit.NANOSECONDS);
}
return result;
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
======io.lettuce.core.internal.Futures
public static <T> T awaitOrCancel(RedisFuture<T> cmd, long timeout, TimeUnit unit) {
try {
if (timeout > 0 && !cmd.await(timeout, unit)) {
cmd.cancel(true);
throw ExceptionFactory.createTimeoutException(Duration.ofNanos(unit.toNanos(timeout)));
}
return cmd.get();
} catch (Exception e) {
throw Exceptions.bubble(e);
}
}
====向redis发送指令
====io.lettuce.core.protocol.CommandHandler
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if (debugEnabled) {
logger.debug("{} write(ctx, {}, promise)", logPrefix(), msg);
}
if (msg instanceof RedisCommand) {
//向redis发送指令,并将RedisCommand入栈到stack中
writeSingleCommand(ctx, (RedisCommand<?, ?, ?>) msg, promise);
return;
}
if (msg instanceof List) {
List<RedisCommand<?, ?, ?>> batch = (List<RedisCommand<?, ?, ?>>) msg;
if (batch.size() == 1) {
writeSingleCommand(ctx, batch.get(0), promise);
return;
}
writeBatch(ctx, batch, promise);
return;
}
if (msg instanceof Collection) {
writeBatch(ctx, (Collection<RedisCommand<?, ?, ?>>) msg, promise);
}
}
private void addToStack(RedisCommand<?, ?, ?> command, ChannelPromise promise) {
try {
validateWrite(1);
if (command.getOutput() == null) {
// fire&forget commands are excluded from metrics
complete(command);
}
RedisCommand<?, ?, ?> redisCommand = potentiallyWrapLatencyCommand(command);
if (promise.isVoid()) {
stack.add(redisCommand);
} else {
promise.addListener(AddToStack.newInstance(stack, redisCommand));
}
} catch (Exception e) {
command.completeExceptionally(e);
throw e;
}
}
接收redis消息
=====io.lettuce.core.protocol.CommandHandler
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws InterruptedException {
if (pristine) {
if (stack.isEmpty() && buffer.isReadable() && !isPushDecode(buffer)) {
if (debugEnabled) {
logger.debug("{} Received response without a command context (empty stack)", logPrefix());
}
if (consumeResponse(buffer)) {
pristine = false;
}
return;
}
}
while (canDecode(buffer)) {
if (isPushDecode(buffer)) {
if (pushOutput == null) {
pushOutput = new PushOutput<>(ByteBufferCopyCodec.INSTANCE);
}
try {
if (!decode(ctx, buffer, pushOutput)) {
hasDecodeProgress = true;
decodeBufferPolicy.afterPartialDecode(buffer);
return;
}
} catch (Exception e) {
ctx.close();
throw e;
}
hasDecodeProgress = false;
PushOutput<ByteBuffer, ByteBuffer> output = pushOutput;
pushOutput = null;
notifyPushListeners(output);
} else {
//从stack出栈一个命令 并将接收的消息内容设置到command的结果里
RedisCommand<?, ?, ?> command = stack.peek();
if (debugEnabled) {
logger.debug("{} Stack contains: {} commands", logPrefix(), stack.size());
}
pristine = false;
try {
if (!decode(ctx, buffer, command)) {
hasDecodeProgress = true;
decodeBufferPolicy.afterPartialDecode(buffer);
return;
}
} catch (Exception e) {
ctx.close();
throw e;
}
hasDecodeProgress = false;
if (isProtectedMode(command)) {
onProtectedMode(command.getOutput().getError());
} else {
if (canComplete(command)) {
stack.poll();
try {
if (debugEnabled) {
logger.debug("{} Completing command {}", logPrefix(), command);
}
complete(command);
} catch (Exception e) {
logger.warn("{} Unexpected exception during request: {}", logPrefix, e.toString(), e);
}
}
}
afterDecode(ctx, command);
}
}
decodeBufferPolicy.afterDecoding(buffer);
}