SpringBoot基于SpringDataRedis配置RedisTemplate
-
JdkSerializationRedisSerializer,所有参与序列化的类必须实现
Serializable
标记接口-
普通对象 + 普通泛型(支持)
-
普通对象 + LocalDateTime泛型(支持)
优点:它是SpringDataRedis的RedisTemplate默认序列化器,针对各种类型都能方便地实现序列化和反序列化,泛型支持完整。
缺点:速度较慢,压缩率较低,可读性差。
# 这是JDK序列化一个hash结构后的二进制结果 key = xacxedx00x05tx00x0d1614414476908 hashKey = xacxedx00x05tx00x11hkey1614414476908 hashValue = xacxedx00x05srx00'com.yang.springdataredisopt.entity.Userxb5x86zxf8xc7xde~\x02x00x03Lx00x02idtx00x13Ljava/lang/Integer;Lx00x04nametx00x12Ljava/lang/String;Lx00x08timeListtx00x10Ljava/util/List;xpsrx00x11java.lang.Integerx12xe2xa0xa4xf7x81x878x02x00x01Ix00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x00x01tx00x04yangsrx00x13java.util.ArrayListxx81xd2x1dx99xc7ax9dx03x00x01Ix00x04sizexpx00x00x00x02wx04x00x00x00x02srx00x0djava.time.Serx95]x84xbax1b"Hxb2x0cx00x00xpwx0ex05x00x00x07xe5x02x1bx10x1b86x1exfbx00xsqx00~x00x0bwx0ex05x00x00x07xe5x02x1bx10x1b86x1exfbx00xx
-
-
Jackson2JsonRedisSerializer
-
普通对象 + 普通泛型:序列化成功,需加ObjectMapper,否则反序列化失败。若加ObjectMapper,则JSON串中会包含类型信息。
-
普通对象 + LocalDateTime泛型:序列化成功,加了ObjectMapper,仍然反序列化失败。若加ObjectMapper,则JSON串中会包含类型信息。
优点:效率高,可读性好。
缺点:泛型支持不完整。
-
-
GenericJackson2JsonRedisSerializer【推荐使用】
-
普通对象 + 普通泛型:序列化、反序列化均成功,即使不加ObjectMapper,JSON串中也包含类型信息。
-
普通对象 + LocalDateTime泛型:序列化成功,需加ObjectMapper,否则反序列化失败。
优点:可读性高,泛型支持完整。
缺点:效率稍低。
-
-
还有一种实现就是直接使用StringRedisTemplate,SpringDataRedis提供了现成的实现,key和value的序列化器都是StringRedisSerializer。写入Redis时,手动将value对象序列化为JSON串后存入Redis;读取时直接读出JSON串,再手动反序列化为value对象。
-
配置及示例
package com.yang.springdataredisopt.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.net.UnknownHostException; /** * @author: Yang * @date: 2018/10/16 22:11 * @description: 只配置了用于Redis服务端交互的模板配置 */ @Configuration public class RedisConfig { /** * 这是一个比较标准的Redis模板配置样例 * * @param redisConnectionFactory * @return */ @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { //1.实例化序列化组件,此处用jackson Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); //【注意:在一个项目中的多重模板应该尽量保持key和hkey的序列化组件一致, // 这样才能保证不同模板对key的操作是一致的,不会出现一种模板放的key另外一种模板拿不到的问题】 RedisSerializer<String> stringSerializer = new StringRedisSerializer(); //2.实例化Jackson的json映射器并配属性 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); //3.将json映射器配置给序列化组件 jackson2JsonRedisSerializer.setObjectMapper(om); //4.实例化Redis模板,并为之配置连接工厂 RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); //5.给模板配置序列化组建 template.setKeySerializer(stringSerializer); template.setHashKeySerializer(stringSerializer); template.setValueSerializer(jackson2JsonRedisSerializer); template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } /** * 泛型支持良好的序列化器【推荐使用】 * * @param redisTemplate * @return */ @Bean public RedisTemplate<String, Object> genericRedisTemplate(RedisTemplate redisTemplate) { RedisSerializer stringSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(stringSerializer); redisTemplate.setHashKeySerializer(stringSerializer); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); objectMapper.registerModule(new JavaTimeModule()); objectMapper.registerModule((new SimpleModule())); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(objectMapper); redisTemplate.setValueSerializer(serializer); redisTemplate.setHashValueSerializer(serializer); return redisTemplate; } /** * String类型模板实例化处,这里使用Spring-data-redis内置提供的模板类 * * @param redisConnectionFactory * @return * @throws UnknownHostException */ @Bean @ConditionalOnMissingBean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { return new StringRedisTemplate(redisConnectionFactory); } }
package com.yang.springdataredisopt.rest; import com.yang.springdataredisopt.entity.Student; import com.yang.springdataredisopt.entity.User; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; /** * @author: Yang * @date: 2021/2/27 14:25 * @description: */ @RestController @RequestMapping("/serializer") public class SerializerController { @Resource private RedisTemplate<String, Object> genericRedisTemplate; @Resource private StringRedisTemplate stringRedisTemplate; @GetMapping("/get") public Object get() { List<LocalDateTime> kk = new ArrayList<>(2); kk.add(LocalDateTime.now()); kk.add(LocalDateTime.now()); User user = User.builder().id(1).name("yang").timeList(kk).build(); String key = String.valueOf(System.currentTimeMillis()); String hkey = String.valueOf("hkey" + System.currentTimeMillis()); genericRedisTemplate.opsForHash().put(key, hkey, user); User obj = (User) genericRedisTemplate.opsForHash().get(key, hkey); return obj; } @GetMapping("/get0") public Object get0() { List<Student> kk = new ArrayList<>(2); kk.add(new Student()); kk.add(new Student()); User user = User.builder().id(1).name("yang").studentList(kk).build(); String key = String.valueOf(System.currentTimeMillis()); String hkey = String.valueOf("hkey" + System.currentTimeMillis()); genericRedisTemplate.opsForHash().put(key, hkey, user); User obj = (User) genericRedisTemplate.opsForHash().get(key, hkey); return obj; } @GetMapping("/init") public void init() { } }
package com.yang.springdataredisopt.entity; import lombok.Builder; import lombok.Data; import java.io.Serializable; import java.time.LocalDateTime; import java.util.List; /** * @author: Yang * @date: 2018/10/21 23:56 * @description: */ @Data @Builder public class User implements Serializable { private Integer id; private String name; private List<Student> studentList; private List<LocalDateTime> timeList; } package com.yang.springdataredisopt.entity; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * @author: Yang * @date: 2018/10/22 01:37 * @description: */ @Data @NoArgsConstructor public class Student implements Serializable { private String clazz; private String teacher; }