Redis Jedis原理 自定义Redis客户端

通常我们调用Jedis提供的API来操作Redis,本文将手写一个简单的Redis客户端,实现Jedis的set、get和incr功能。

用Jedis连接NIO服务端,发送指令

NIO服务端以前写过,代码就不贴了,可参考此链接Java基础 BIO & NIO 设计思想

JedisTest类
package com.tbryant.jedistest;

import redis.clients.jedis.Jedis;

public class JedisTest {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1", 8888);
        System.out.println(jedis.set("tonny", "bryant"));
        System.out.println(jedis.get("tonny"));
        System.out.println(jedis.incr("count"));
    }
}
运行结果

NIO服务端
*:星号是开始符,3表示后面跟着3组指令,每2行组成一个指令。
$:dollar符后面跟数字,表示指令长度。
Jedis客户端
由此可见Jedis连接NIO服务端成功,并发送set方法对应的三组指令,但未收到服务端的返回数据,最终超时异常关闭连接。

自定义Redis Client

角色划分

常量类:存储指令符号和操作谓词。
自定义Socket类:用于发送和读取数据。
自定义RedisClient类:提供API操作Redis。
测试类:使用自定义RedisClient与Redis交互。

Constant类
package com.tbryant.customredisclient;

public class Constant {
    public static final String START = "*";// 开始符
    public static final String LENGTH = "$";// 指令长度符
    public static final String LINE = "\r\n";// 换行符

    public enum command {
        SET,
        GET,
        INCR
    }
}
CustomSocket类
package com.tbryant.customredisclient;

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

public class CustomSocket {
    private Socket socket;
    private InputStream inputStream;
    private OutputStream outputStream;

    public CustomSocket(String ip, int port) {
        try {
            socket = new Socket(ip, port);
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 把拼接完的指令发送给redis
    public void send(String cmd) {
        try {
            outputStream.write(cmd.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 接收redis返回的数据
    public String read() {
        byte[] bytes = new byte[1024];// TODO 处理超过1024的返回数据
        int count = 0;
        try {
            count = inputStream.read(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new String(bytes, 0, count);
    }
}
CustomRedisClient类
package com.tbryant.customredisclient;

public class CustomRedisClient {
    private CustomSocket redisSocket;

    public CustomRedisClient(String host, int port) {
        redisSocket = new CustomSocket(host, port);
    }

    public String set(String key, String value) {
        redisSocket.send(convertToCommand(Constant.command.SET, key.getBytes(), value.getBytes()));
        return redisSocket.read();
    }

    public String get(String key) {
        redisSocket.send(convertToCommand(Constant.command.GET, key.getBytes()));
        return redisSocket.read();
    }

    public String incr(String key) {
        redisSocket.send(convertToCommand(Constant.command.INCR, key.getBytes()));
        return redisSocket.read();
    }

    public static String convertToCommand(Constant.command command, byte[]... bytes) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(Constant.START).append(bytes.length + 1).append(Constant.LINE);
        stringBuilder.append(Constant.LENGTH).append(command.toString().length()).append(Constant.LINE);
        stringBuilder.append(command.toString()).append(Constant.LINE);
        for (byte[] aByte : bytes) {
            stringBuilder.append(Constant.LENGTH).append(aByte.length).append(Constant.LINE);
            stringBuilder.append(new String(aByte)).append(Constant.LINE);
        }
        return stringBuilder.toString();
    }
}

Application类
package com.tbryant.customredisclient;

public class Application {
    public static void main(String[] args) {
        CustomRedisClient redisClient = new CustomRedisClient("127.0.0.1", 6379);
        System.out.println(redisClient.set("tonny", "bryant"));
        System.out.println(redisClient.get("tonny"));
        System.out.println(redisClient.incr("count"));
    }
}

测试代码用CustomRedisClient替换Jedis,端口号指向Redis服务端,其他代码与JedisTest保持一致。

运行结果

Application Test
操作Redis成功,并接收到Redis返回数据。查看Redis官网可以得知Redis遵循RESP协议,该协议规定Redis返回符号定义:
+:加号后面跟简单字符串。
-:减号后面跟错误信息。
::冒号后面跟int类型。
$:doller符后面跟长字符串。
*:星号后面跟数组。
源码地址:CustomJedis模块

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值