Redis实现自定义序列化方式
1. 如何实现redis的序列化?
序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
序列化主要用于存储对象状态为另一种通用格式,比如存储为二进制、xml、json等等,把对象转换成这种格式就叫序列化,而反序列化通常是从这种格式转换回来。
使用序列化主要是因为跨平台和对象存储的需求,因为网络上只允许字符串或者二进制格式,而文件需要使用二进制流格式,如果想把一个内存中的对象存储下来就必须使用序列化转换为xml(字符串)、json(字符串)或二进制(流)
我们看看源码:redis的key和value为什么需要序列化?如何序列化?
① RedisAutoConfiguration的源码: Redis为我们提供了两个模板类RedisTemplate和StringRedisTemplate:
public class RedisAutoConfiguration {
public RedisAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
//RedisTemplate的key和value都是Object类型的,如果进行网络传输或将数据存储到硬盘上就需对key和value进行序列化
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
② StringRedisTemplate的源码:可以看出他的键和值都只支持String类型
//StringRedisTemplate类继承RedisTemplate<String, String>
public class StringRedisTemplate extends RedisTemplate<String, String> {
//将key和value都序列化为String类型的,也是只支持String类型的key和value
public StringRedisTemplate() {
this.setKeySerializer(RedisSerializer.string());
this.setValueSerializer(RedisSerializer.string());
this.setHashKeySerializer(RedisSerializer.string());
this.setHashValueSerializer(RedisSerializer.string());
}
}
③ RedisSerializer 的源码:可以看到redis提供的几种序列化方式:
StringRedisTemplate默认采用的是String的序列化策略**(StringRedisSerializer),保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略(JdkSerializationRedisSerializer)**,保存的key和value都是采用此策略序列化保存的。用JdkSerializationRedisSerializer序列化的话,被序列化的对象必须实现Serializable接口。在存储内容时,除了属性的内容外还存了其它内容在里面,总长度长,且不容易阅读。
public interface RedisSerializer<T> {
@Nullable
byte[] serialize(@Nullable T var1) throws SerializationException;
@Nullable
T deserialize(@Nullable byte[] var1) throws SerializationException;
static RedisSerializer<Object> java() {
return java((ClassLoader)null);
}
static RedisSerializer<Object> java(@Nullable ClassLoader classLoader) {
return new JdkSerializationRedisSerializer(classLoader);
}
//保存对象为json,它不仅可以将对象序列化,还可以将对象转换为json字符串并保存到redis中,但需要和jackson配合一起使用。
static RedisSerializer<Object> json() {
return new GenericJackson2JsonRedisSerializer();
}
//将String字符串对象序列化为二进制字节数组,底层使用的StringRedisSerializer
static RedisSerializer<String> string() {
return StringRedisSerializer.UTF_8;
}
}
RedisTemplate的key和value都支持Object类型;而StringRedisTemplate的key和value都支持String类型;现在我们希望Redis的key支持String类型,value支持Object类型:
key和hashKey : 推荐使用 StringRedisSerializer: 简单的字符串序列化;
value和hashValue: 推荐使用 GenericJackson2JsonRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 设置key的序列化方式
template.setKeySerializer(RedisSerializer.string());
// 设置value的序列化方式
template.setValueSerializer(RedisSerializer.json());
// 设置hash的key的序列化方式
template.setHashKeySerializer(RedisSerializer.string());
// 设置hash的value的序列化方式
template.setHashValueSerializer(RedisSerializer.json());
template.afterPropertiesSet();
return template;
}
}
除此之外,还可以模仿StringRedisTemplate的序列化方式,自定义序列化方式对Object对象进行序列化:
StringRedisSerializer的源码:将String序列化为二进制byte数组;
public class StringRedisSerializer implements RedisSerializer<String> {
private final Charset charset;
public static final StringRedisSerializer US_ASCII;
public static final StringRedisSerializer ISO_8859_1;
public static final StringRedisSerializer UTF_8;
public StringRedisSerializer() {
this(StandardCharsets.UTF_8);
}
public StringRedisSerializer(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
}
//将字节数组反序列化为String字符串
public String deserialize(@Nullable byte[] bytes) {
return bytes == null ? null : new String(bytes, this.charset);
}
//将String序列化为二进制byte[]数组
public byte[] serialize(@Nullable String string) {
return string == null ? null : string.getBytes(this.charset);
}
static {
US_ASCII = new StringRedisSerializer(StandardCharsets.US_ASCII);
ISO_8859_1 = new StringRedisSerializer(StandardCharsets.ISO_8859_1);
UTF_8 = new StringRedisSerializer(StandardCharsets.UTF_8);
}
}
模仿StringRedisTemplate的序列化实现源码,对Object对象进行序列化:
public class MyStringRedisSerializer implements RedisSerializer<Object> {
private final Charset charset;
public MyStringRedisSerializer() {
this(StandardCharsets.UTF_8);
}
public MyStringRedisSerializer(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
}
@Override
public String deserialize(byte[] bytes) {
return (bytes == null ? null : new String(bytes, charset));
}
//将对象序列化为byte[]数组
@Override
public byte[] serialize(Object object) {
//如果这个对象为null
if (object == null) {
return new byte[0];
}
//如果这个对象时String类型
if (object instanceof String) {
return object.toString().getBytes(charset);
//如果这个对象不是String类型,就将这个对象转换为String类型后,然后转成byte字节数组
} else {
String string = JSON.toJSONString(object);
return string.getBytes(charset);
}
}
}
配置一个RedisTemplate<String,Object>
到Spring容器中:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
//key--String:定义一个 StringRedisSerializer
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//value---Object:定义一个 MyStringRedisSerializer
MyStringRedisSerializer myStringRedisSerializer = new MyStringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(myStringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(myStringRedisSerializer);
return redisTemplate;
}
}
本文地址:https://blog.csdn.net/qq_42764468/article/details/107685639
推荐阅读
-
Java Redis分布式锁的正确实现方式详解
-
Python使用redis pool的一种单例实现方式
-
php实现Mongodb自定义方式生成自增ID的方法
-
Map集合的遍历方式以及TreeMap集合保存自定义对象实现比较的Comparable和Comparator两种方式
-
Android中自定义View的实现方式总结大全
-
SpringBoot2.3整合redis缓存自定义序列化的实现
-
Spring Boot分布式系统实践【扩展1】shiro+redis实现session共享、simplesession反序列化失败的问题定位及反思改进
-
redis Jedis序列化自定义存储list对象和map数据
-
springboot aop 自定义注解方式实现一套完善的日志记录(完整源码)
-
深入理解 Redis Template及4种序列化方式