中间件-缓存之Redis

118 阅读2分钟

1. 缓存

1.1 Redis

1.1.1 Redis服务

下载Redis安装包,切换至下载目录,命令行启动Redis服务;

redis-server redis.windows.conf

1.1.2 Jedis

Java与Redis交互可以使用Jedis,Jedis实现了与Redis通信的协议RESP(REdis Serialization Protocol),封装了与Redis服务器进行交互的细节,提供简单一致的接口;

以Jedis中的get方法为例:

public String get(String key) {
    this.checkIsInMultiOrPipeline();
    this.client.get(key);
    return this.client.getBulkReply();
}

其中Jedis通信协议相关实现主要在protocol类中,Jedis调用sendCommand发送指令,主要是按通信协议进行报文格式的封装;

    private static void sendCommand(RedisOutputStream os, byte[] command, byte[]... args) {
        try {
            os.write((byte)42);
            os.writeIntCrLf(args.length + 1);
            os.write((byte)36);
            os.writeIntCrLf(command.length);
            os.write(command);
            os.writeCrLf();
            byte[][] var3 = args;
            int var4 = args.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                byte[] arg = var3[var5];
                os.write((byte)36);
                os.writeIntCrLf(arg.length);
                os.write(arg);
                os.writeCrLf();
            }

        } catch (IOException var7) {
            throw new JedisConnectionException(var7);
        }
    }

而Redis的解码则在Protocol类的process执行,通过响应的第一个字节来标志报文的类型;

private static Object process(RedisInputStream is) {
    byte b = is.readByte();
    switch(b) {
    case 36:
        return processBulkReply(is);
    case 42:
        return processMultiBulkReply(is);
    case 43:
        return processStatusCodeReply(is);
    case 45:
        processError(is);
        return null;
    case 58:
        return processInteger(is);
    default:
        throw new JedisConnectionException("Unknown reply: " + (char)b);
    }
}

get方法调用的processBulkReply函数如下,可以看到返回的是byte[]

    private static byte[] processBulkReply(RedisInputStream is) {
        int len = is.readIntCrLf();
        if (len == -1) {
            return null;
        } else {
            byte[] read = new byte[len];
            int size;
            for(int offset = 0; offset < len; offset += size) {
                size = is.read(read, offset, len - offset);
                if (size == -1) {
                    throw new JedisConnectionException("It seems like server has closed the connection.");
                }
            }
            is.readByte();
            is.readByte();
            return read;
        }
    }

1.1.3 代码示例

可以将字符串存入Redis,也可以将对象序列化之后存入Redis

public class RedisConn {
    public static class Dog implements Serializable {
        private String kind;
        public  Dog(String kind){
            this.kind = kind;
        }
        public String toString(){
            return "Dog Type:"+kind;
        }
    }
    public static void main(String[] args){
        Jedis jedisCli = new Jedis("localhost");
        System.out.println("服务正在运行"+jedisCli.ping());
        jedisCli.set("myName","Alan");
        String name = jedisCli.get("myName");
        System.out.println("Dict value:"+name);
        jedisCli.set("obj".getBytes(),SerializeUtil.serialize(new RedisConn.Dog("wolf dog")));
        RedisConn.Dog dog1 =(Dog)SerializeUtil.deserialize(jedisCli.get("obj".getBytes()));
        System.out.println(dog1.toString());
        jedisCli.close();
    }
}

序列化工具类SerializeUtil

ublic class SerializeUtil {
	//序列化
    public static byte[] serialize(Object object) {
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            byte[] bytes = baos.toByteArray();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (baos != null) {
                    baos.close();
                }
                if (oos != null) {
                    oos.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return null;
    }
	//反序列化
    public static Object deserialize(byte[] bytes) {
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try {
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bais != null) {
                    bais.close();
                }
                if (ois != null) {
                    ois.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return null;
    }
}

输出如下:

服务正在运行PONG
Dict value:Alan
Dog Type:wolf dog

1.1.4 可视化工具

Redis Desktop Manager,对象是以二进制的方式存储在Redis中