手写Jedis

简介

Redis缓存技术常备作为互联网架构中的热点技术,常用来提升系统的性能,常被应用在一些读多写少的场景。Jedis基于Java实现,通过Jedis底层的协议,我们很简单就可以访问Redis服务器,如Redis中的Set、keys、get等命令。本文将简单模拟Jedis的实现。

原理

Redis使用RESP协议,其描述如下:
Jedis协议地址
在这里插入图片描述
验证:
我们可以手写一个ServerSocket,让Jedis连接我们的ServerSocket,然后ServerSocket将受到的消息打印出来。
在这里插入图片描述
如我们使用Set命令,在RESP协议中,传输内容如下:

# set("iname", "zhanghaolin") 
*3        # *代表数组个数
$3        # $表示下一个字符串的长度
SET       # 命令
$5
iname
$11
zhanghaolin

代码实现

在这里插入图片描述
Jedis中将API分了三层,分别为传输层,协议层和API层。传输层主要使用Socket进行通信,协议层主要对要发送的对象进行包装,API层主要开放接口给调用者。在我的代码中分别对应connection、protocol、client。以上为Jedis的核心层,另外还可增加一些其他层,如安全编码等,如文中的safe。

1、Connection层

package org.redis.connection;

import org.redis.protocol.Protocol;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Connection {
    private String host;
    private int port;
    private Socket socket;
    private InputStream is;
    private OutputStream os;

    public Connection(String host, int port) {
        this.host = host;
        this.port = port;
    }


    private void connect(){
        try {
            if(!isConnected()){
                socket = new Socket(host,port);
                this.is = socket.getInputStream();
                this.os = socket.getOutputStream();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private boolean isConnected(){
        return this.socket != null && this.socket.isBound() && !this.socket.isClosed() && this.socket.isConnected();
    }

    public void sendCommand(Protocol.Command command,byte []... bytes){
        connect();
        Protocol.sendCommand(os,command,bytes);
    }

    public String replyCodeString(){
        byte [] bytes = new byte[1024];
        try {
            is.read(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new String(bytes);
    }

    public void close(){
        try {
            if(os != null){
                os.close();
            }
            if(is != null){
                is.close();
            }
            if(socket != null){
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2、Protocol层

package org.redis.protocol;

import java.io.IOException;
import java.io.OutputStream;

public class Protocol {
    private static final String DOLLER_STRING = "$";
    private static final String ALERSTIC_STRING = "*";
    private static final String CTLF_STRING = "\r\n";

    public static void sendCommand(OutputStream os,Command command,byte [] ... bytes){
        StringBuilder builder = new StringBuilder();
        builder.append(ALERSTIC_STRING).append(bytes.length + 1).append(CTLF_STRING);
        builder.append(DOLLER_STRING).append(command.name().length()).append(CTLF_STRING);
        builder.append(command.name()).append(CTLF_STRING);
        for(byte [] arg:bytes){
            builder.append(DOLLER_STRING).append(arg.length).append(CTLF_STRING);
            builder.append(new String(arg)).append(CTLF_STRING);
        }
        try {
            os.write(builder.toString().getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static enum Command{
        SET,GET,INCR,KEYS
    }
}

3、client层

package org.redis.client;

import org.redis.connection.Connection;
import org.redis.protocol.Protocol;

public class Client {

    private Connection connection;
    public Client(String host,int port){
        this.connection = new Connection(host,port);
    }

    public String set(String key, String value){
        connection.sendCommand(Protocol.Command.SET,key.getBytes(),value.getBytes());
        return connection.replyCodeString();
    }

    public String get(String key){
        connection.sendCommand(Protocol.Command.GET,key.getBytes());
        return connection.replyCodeString();
    }

    public String incr(){
        return null;
    }

    public void close() {
        if(connection != null) connection.close();
    }
}

4、safe层

package org.redis.safe;

import java.io.UnsupportedEncodingException;

public class SaveEncoding {
    public static byte [] encode(String string){
        if(string == null){
            throw new NullPointerException("encode字符串不能为空");
        }
        try {
            return string.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

总结

本文简要介绍了Jedis以及RESP协议,并提供了其Java版本的简单实现。

参考文献

https://blog.csdn.net/weixin_35586546/article/details/85256635

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值