拆解的项目源码地址:
https://github.com/xk4848123/ef-redis
感谢开源!!!
如何剖析一个项目之Redis(一)
如何剖析一个项目之Redis(二)
如何剖析一个项目之Redis(三)
已知
这是一款阉割的Java版的redis,通信基于Netty编写。
已知的未知(该篇我们能学到什么)
一个命令被该系统接收到后,是如何处理然后又返回的。
解决已知的未知
我们先准备一个redis-client(我这里用的Windows)。
下载完成后,我们开始调试这个java版的redis。
用这个main方法来启动该redis服务!
redis已启动!!!
可以看出启动时候实际上是启动了一个Netty的服务端,redis-cli客户端首先会建立网络连接,然后通过该连接发送命令,这里首先会使用CommandDecoder来解码。
public class CommandDecoder extends LengthFieldBasedFrameDecoder
{
private static final Logger LOGGER = Logger.getLogger(CommandDecoder.class);
private static final int MAX_FRAME_LENGTH = Integer.MAX_VALUE;
private Aof aof=null;
// static {
// if(PropertiesUtil.getAppendOnly()) {
// aof=new Aof();
// }
// }
public CommandDecoder(Aof aof){
this();
this.aof=aof;
}
public CommandDecoder() {
super(MAX_FRAME_LENGTH, 0, 4);
}
@Override
public Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
TRACEID.newTraceId();
while (in.readableBytes() != 0)
{
int mark = in.readerIndex();
try
{
Resp resp = Resp.decode(in);
if (!(resp instanceof RespArray||resp instanceof SimpleString))
{
throw new IllegalStateException("客户端发送的命令应该只能是Resp Array 和 单行命令 类型");
}
Command command=null;
if(resp instanceof RespArray) {
command = CommandFactory.from((RespArray) resp);
}else if(resp instanceof SimpleString){
command = CommandFactory.from((SimpleString) resp);
}
if (command == null)
{
//取出命令
ctx.writeAndFlush(new Errors("unsupport command:" + ((BulkString) ((RespArray) resp).getArray()[0]).getContent().toUtf8String()));
}
else
{
if (aof!=null&&command instanceof WriteCommand) {
aof.put(resp);
}
return command;
}
}
catch (Exception e)
{
in.readerIndex(mark);
LOGGER.error("解码命令", e);
break;
}
}
return null;
}
LengthFieldBasedFrameDecoder快速了解
使用redis-cli发送命令:set hello world。
redis通信协议详细指南
这一条命令按照通信协议会呈现出这种样子。
*3
$3
SET
$5
hello
$7
world
redis-cli发出命令后CommandDecoder的decode方法会被调用,该方法中会调用Resp的decode静态方法解析命令。
static Resp decode(ByteBuf buffer) {
if (buffer.readableBytes() <= 0) {
new IllegalStateException("没有读取到完整的命令");
}
char c = (char) buffer.readByte();
if (c == RespType.STATUS.getCode()) {
return new SimpleString(getString(buffer));
} else if (c == RespType.ERROR.getCode()) {
return new Errors(getString(buffer));
} else if (c == RespType.INTEGER.getCode()) {
int value = getNumber(buffer);
return new RespInt(value);
} else if (c == RespType.BULK.getCode()) {
int length = getNumber(buffer);
if (buffer.readableBytes() < length + 2) {
throw new IllegalStateException("没有读取到完整的命令");
}
byte[] content;
if (length == -1) {
content = null;
} else {
content = new byte[length];
buffer.readBytes(content);
}
if (buffer.readByte() != RespType.R.getCode() || buf