【ITer自我修养之成长日记】Redis的java API操作

it2024-11-19  1

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 验证

最新回复(0)