Redis的java API操作
一、导入依赖二、redis架构示意图三、徒手解剖redis1.Test1.1 运行redis-server和redis-cli1.2 编码1.3 redis-cli端查看
2. 模拟redis服务端 -- HackSockerServer2.1 编码2.2 Test 测试类分别运行HackSockerServer和Test结果官网说明 https://redis.io/topics/protocol那么以上结果可以理解为:
3.transfer层原理+编码3.1 编码
4.根据以上理解模拟protocol层(协议层)4.1 编码
5.根据以上理解模拟client层(API层)5.1 编码
6.结果验证6.2 SET 的Test 测试类6.2 SET 的结果6.3 GET 的Test 测试类6.4 redis-cli 验证6.5 GET 的结果6.6 redis-cli 验证
一、导入依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
二、redis架构示意图
三、徒手解剖redis
1.Test
1.1 运行redis-server和redis-cli
1.2 编码
package cn.redis;
import redis.clients.jedis.Jedis;
public class Test {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost");
jedis.set("myname", "LQ");
System.out.println(jedis.get("myname"));
}
}
1.3 redis-cli端查看
2. 模拟redis服务端 – HackSockerServer
2.1 编码
package cn.redis.hack;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 伪装 redis 的服务端
*
* */
public class HackSockerServer {
public static void main(String[] args) throws IOException {
System.out.println("HackSockerServer已启动.....");
ServerSocket serverSocket = new ServerSocket(6379);
//接收数据
Socket accept = serverSocket.accept();
byte[] buffer = new byte[1024];
accept.getInputStream().read(buffer);
System.out.println(new String(buffer));
}
}
2.2 Test 测试类
package cn.redis;
import redis.clients.jedis.Jedis;
public class Test {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost");
jedis.set("myname", "LQ");
System.out.println(jedis.get("myname"));
}
}
分别运行HackSockerServer和Test
结果
HackSockerServer已启动.....
*3
$3
SET
$6
myname
$2
LQ
官网说明 https://redis.io/topics/protocol
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 "*" -->数组
Simple Strings are encoded in the following way: a plus character, followed by a string that cannot contain a CR or LF character (no newlines are allowed), terminated by CRLF (that is "\r\n").
那么以上结果可以理解为:
*3 3个数组
=====
$3 3个字符串
SET
===========
$6 6个字符串
myname
===========
$2 2个字符串
LQ
===========
3.transfer层原理+编码
3.1 编码
package cn.redis.transfer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Conncetion {
private Socket socket;
private String host;
private int port;
private OutputStream outputStream;
private InputStream inputStream;
public Conncetion(String host, int port) {
this.host = host;
this.port = port;
}
public void connect() throws IOException {
try {
socket = new Socket(host, port);
inputStream = socket.getInputStream();
outputStream=socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.根据以上理解模拟protocol层(协议层)
4.1 编码
package cn.redis.protocol;
/*
* 模拟协议层工作原理:加入命令格式如下
*3
$3
SET
$6
myname
$2
LQ
* */
import java.io.IOException;
import java.io.OutputStream;
public class Protocol {
public static final String ASTERISK_STRING = "*"; //asterisk --> 星号
public static final String DOLLAR_STRING = "$";
public static final String BLANK_STRING = "\r\n";
public static enum Command{
GET,SET
}
public static void protocolAnalysis(OutputStream os, Protocol.Command command, byte[]...args) {
StringBuilder sb = new StringBuilder();
sb.append(ASTERISK_STRING).append(args.length + 1).append(BLANK_STRING); //相当于 *3
sb.append(DOLLAR_STRING).append(command.name().length()).append(BLANK_STRING); //相当于 $3
sb.append(command.name()).append(BLANK_STRING); //相当于 SET
for (byte[] arg : args) {
sb.append(DOLLAR_STRING).append(arg.length).append(BLANK_STRING);
sb.append(new String(arg)).append(BLANK_STRING);
}
System.out.println(sb.toString());
try {
os.write(sb.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.根据以上理解模拟client层(API层)
5.1 编码
package cn.redis.client;
import cn.redis.protocol.Protocol;
import cn.redis.safe.SafeEncode;
import cn.redis.transfer.Transfer;
import redis.clients.util.SafeEncoder;
import java.io.IOException;
/**
* 暴露给其他人进行调用的
* */
public class ClinetOp {
private Transfer conncetion;
//连接
public ClinetOp(String host, int port) {
conncetion = new Transfer(host, port);
}
//暴露此调用接口,此调用接口的底层 还是要去操作 redis, 所以构造方法如上
//在写 GET 方法时,想到返回信息,所以 另写了getStatusReply()
public String set(String key, String value) throws IOException {
conncetion.sendCommand(Protocol.Command.SET, SafeEncoder.encode(key), SafeEncoder.encode(value));
return conncetion.getStatusReply();
}
//在理解 SET 方法的基础上,写GET方法,向 架构师 方向更进一步
public String get(String key) throws IOException {
conncetion.sendCommand(Protocol.Command.GET, SafeEncoder.encode(key));
return conncetion.getStatusReply();
}
}
6.结果验证
6.2 SET 的Test 测试类
package cn.redis;
import cn.redis.client.ClinetOp;
import redis.clients.jedis.Jedis;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
/**
* 自己实现 redis 的架构 由上到下
* 1.API层 client
* 2.协议层 protocol
* 3.传输层 transfer
* */
ClinetOp clinetOp = new ClinetOp("192.168.1.100",6379);
clinetOp.set("mytest", "success");
//System.out.println(clinetOp.get("mytest"));
}
}
6.2 SET 的结果
*3
$3
SET
$6
mytest
$7
success
6.3 GET 的Test 测试类
package cn.redis;
import cn.redis.client.ClinetOp;
import redis.clients.jedis.Jedis;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
/**
* 自己实现 redis 的架构 由上到下
* 1.API层 client
* 2.协议层 protocol
* 3.传输层 transfer
* */
ClinetOp clinetOp = new ClinetOp("192.168.1.100",6379);
clinetOp.set("mytest", "success");
System.out.println(clinetOp.get("mytest"));
}
}
6.4 redis-cli 验证
6.5 GET 的结果
*3
$3
SET
$6
mytest
$7
success
==== 以上是 SET 的结果 =====
*2
$3
GET
$6
mytest
$7
success
==== 以上是 GET 的结果
6.6 redis-cli 验证