JAVA手写实现简单版Jedis客户端----超详细
已更新将手写的Jedis加入到springboot的自动配置,并可实现yml中修改配置
传送门:(将手写Jedis集成到springboot自动配置)
首先写之前,咱们聊聊手写的思路,聊到redis,咱们都知道是一款NOSQL的缓存数据库,可以用来验证登陆,可以存放热点数据,可以用来做秒杀,用来流量销峰。那么redis到底是怎么通信的呢?JAVA又是如何与redis建立连接的呢?
看下图:
搞通了流程图之后,那么有一个问题,网络通信用的是什么协议来进行传输呢?答案是:RESP协议来通信。
那么RESP协议长啥样呢?
例:
*3 数组3
$3 字符3
SET
$6 字符串6
xiangan
字符串4
$4
2020
//"+OK\r\n" 每一个结尾都需要一个换行
//For Simple Strings the first byte of the reply is "+"
//For Errors the first byte of the reply is "-"
//For Integers the first byte of the reply is ":"
//For Bulk Strings the first byte of the reply is "$"
//For Arrays the first byte of the reply is "*"
好了,协议搞明白了,那么我们直接用代码来简单实现一个Jedis客户端吧
需要用到的有3个类,分别解释一下:
TestJedis:API层
TestProtocol:协议格式处理
Connection:连接,发送数据层。
Test测试类:
TestJedis jedis = new TestJedis("*.*.*.*", 6379);
System.out.println(jedis.set("haha", "haha"));
System.out.println(jedis.get("haha"));
TestJedis类:
/**
*
* @author An
* JedisClient API操作层
*
*/
public class TestJedis {
Connection connection; //连接层
public TestJedis(String host,int port) {
//构造方法传入:ip地址和端口号
this.connection = new Connection(host, port);
}
//APIset方法
public String set(String key,String value) {
connection.sendcommit(Command.SET,key.getBytes(),value.getBytes());
return connection.getStatusCodereply();
}
//API get方法
public String get(String key) {
connection.sendcommit(Command.GET,key.getBytes());
return connection.getStatusCodereply();
}
}
Connection类:
/**
*
* @author An
*
*/
public class Connection {
private Socket socket;//socket连接
private String host;//主机ip地址
private int port;//端口号
private OutputStream outputStream;//输出流
private InputStream inputStream;//输入流
public Connection(String host,int port) {
this.host = host;
this.port = port;
}
public Connection connection() {
try {
//建立socket连接
socket = new Socket(host, port);
//获取输入输出流
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return this;
}
/**
* 发送数据和命令
* @return
*/
public Connection sendcommit(Command command,byte[]...bs) {
connection();
TestProtocol.sendCommand(outputStream, command, bs);
return this;
}
/**
* 接收服务端返回的数据
*/
public String getStatusCodereply() {
byte[] bytes = new byte[1024];
try {
inputStream.read(bytes);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new String(bytes);
}
}
TestProtocol类:
/**
*
* @author An
*
* 协议数据格式处理
*
*/
public class TestProtocol {
public static final String DOLLAR_BYTE="$";//字符串
public static final String ASTERISK_BYTE="*";//数组
public static final String BLANK_STRING="\r\n";//换行
//封装redis需要的数据
public static void sendCommand(OutputStream os,Command command,byte[]...bs ) {
StringBuffer sb = new StringBuffer();
sb.append(ASTERISK_BYTE).append(bs.length+1).append(BLANK_STRING);
sb.append(DOLLAR_BYTE).append(command.name().length()).append(BLANK_STRING);
sb.append(command.name()).append(BLANK_STRING);
System.out.println(command.name());
for (byte[] bs2 : bs) {
sb.append(DOLLAR_BYTE).append(bs2.length).append(BLANK_STRING);
sb.append(new String(bs2)).append(BLANK_STRING);
}
try {
//发送
os.write(sb.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
//定义枚举
public static enum Command{
GET,SET,KEYS
}
}
测试一下:
好了,大功告成!!!码字不易,觉得有帮助的,不妨点个赞再走~~~
您的点赞将是作者持续更新的动力!!!!