Jackson 2.x 系列【29】Spring Boot 集成之 Redis 序列化/反序列化
创始人
2024-11-14 03:06:42
0

有道无术,术尚可求,有术无道,止于术。

本系列Jackson 版本 2.17.0

本系列Spring Boot 版本 3.2.4

源码地址:https://gitee.com/pearl-organization/study-jaskson-demo

文章目录

    • 1. 前言
    • 2. RedisTemplate
    • 3. RedisSerializer
      • 3.1 JdkSerializationRedisSerializer
      • 3.2 Jackson2JsonRedisSerializer
    • 4. 案例演示
      • 4.1 创建 RedisTemplate
      • 4.2 创建 ObjectMapper
      • 4.3 创建 Jackson2JsonRedisSerializer
      • 4.4 设置序列化器
      • 4.5 测试

1. 前言

Redis是一个常用的高性能非关系型内存数据库,接下来我们学习在Spring Boot中使用Redis时,集成基于Jackson序列化/反序列化

2. RedisTemplate

RedisTemplate是在Spring Boot环境中和Redis打交道的一个模板类,简化了与Redis数据库的交互过程,我们可以更加便捷地进行Redis的各种操作,如数据存取、异常处理及序列化等。

StringRedisTemplateRedisTemplate的一个扩展,由于大多数针对Redis的操作都是基于字符串的,所以提供了一个专用的类来处理这些操作。

Spring Boot自动配置中,已经帮我们注册了这个两个对象,使用时直接注入即可:

@AutoConfiguration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration {  	@Bean 	@ConditionalOnMissingBean(RedisConnectionDetails.class) 	PropertiesRedisConnectionDetails redisConnectionDetails(RedisProperties properties) { 		return new PropertiesRedisConnectionDetails(properties); 	}  	@Bean 	@ConditionalOnMissingBean(name = "redisTemplate") 	@ConditionalOnSingleCandidate(RedisConnectionFactory.class) 	public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 		RedisTemplate template = new RedisTemplate<>(); 		template.setConnectionFactory(redisConnectionFactory); 		return template; 	}  	@Bean 	@ConditionalOnMissingBean 	@ConditionalOnSingleCandidate(RedisConnectionFactory.class) 	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { 		return new StringRedisTemplate(redisConnectionFactory); 	} } 

3. RedisSerializer

Spring Data声明了RedisSerializer接口,用于处理Redis序列化/反序列化,定义了相应的操作方法:

public interface RedisSerializer {  	// 静态方法,直接返回不同类型的 RedisSerializer 实例     static RedisSerializer java() {         return java((ClassLoader)null);     }      static RedisSerializer java(@Nullable ClassLoader classLoader) {         return new JdkSerializationRedisSerializer(classLoader);     }      static RedisSerializer json() {         return new GenericJackson2JsonRedisSerializer();     }      static RedisSerializer string() {         return StringRedisSerializer.UTF_8;     }      static RedisSerializer byteArray() {         return ByteArrayRedisSerializer.INSTANCE;     } 	 	// 序列化     @Nullable     byte[] serialize(@Nullable T value) throws SerializationException; 	 	// 反序列化     @Nullable     T deserialize(@Nullable byte[] bytes) throws SerializationException;      default boolean canSerialize(Class type) {         return ClassUtils.isAssignable(this.getTargetType(), type);     }      default Class getTargetType() {         return Object.class;     } }  

默认提供了多种RedisSerializer实现:

在这里插入图片描述

简要说明

  • JdkSerializationRedisSerializer :默认配置,使用JDK自带的序列化机制将Java对象序列化为字节数组
  • OxmSerializer:用于序列化和反序列化XML数据
  • ByteArrayRedisSerializer:用于处理字节数组二进制数据,无需进行复杂的对象到字符串的转换,适用于大量二进制数据操作
  • StringRedisSerializer:将Java对象序列化为Redis可以存储的字符串形式
  • GenericToStringSerializer:通用的序列化器类,是将任意类型的数据对象转换为字符串形式,调用对象的toString()方法或自定义的序列化方法来获取字符串表示
  • GenericJackson2JsonRedisSerializer:将Java对象序列化为JSON格式的字符串形式,不需要设置类型信息,能够处理更多的动态类型,灵活性扩展性较低
  • Jackson2JsonRedisSerializer: 将Java对象序列化为JSON格式的字符串形式,必须提供要序列化对象的类型信息,每个类型都创建一个序列化器实例

3.1 JdkSerializationRedisSerializer

JdkSerializationRedisSerializer使用JDK自带的序列化机制,序列化Java对象为字节数组,反序列化字节数组为Java对象,是默认的选项。使用时,Java对象需要实现Serializable接口,存储的数据是不可读的。

核心方法如下:

	// 反序列化      public Object deserialize(@Nullable byte[] bytes) {         if (SerializationUtils.isEmpty(bytes)) {             return null;         } else {             try {                 return this.deserializer.convert(bytes);             } catch (Exception var3) {                 throw new SerializationException("Cannot deserialize", var3);             }         }     } 	// 序列化     public byte[] serialize(@Nullable Object object) {         if (object == null) {             return SerializationUtils.EMPTY_ARRAY;         } else {             try {                 return (byte[])this.serializer.convert(object);             } catch (Exception var3) {                 throw new SerializationException("Cannot serialize", var3);             }         }     } 

这里使用默认提供的RedisTemplate进行存取操作:

    @Autowired     RedisTemplate redisTemplate;      @Test      void testRedisTemplate() {         UserVO userVO = new UserVO();         userVO.setId(1699657986705854464L);         userVO.setUsername("jack");         userVO.setBirthday(new Date());         List roleList = new ArrayList<>();         roleList.add("管理员");         roleList.add("经理");         userVO.setRoleList(roleList);         redisTemplate.opsForValue().set("userVO", userVO);          // 查询         UserVO o = (UserVO)redisTemplate.opsForValue().get("userVO");         System.out.println(o);     } 

Redis中可以看到存储的键值都是不可读的:

在这里插入图片描述

3.2 Jackson2JsonRedisSerializer

Jackson2JsonRedisSerializer是基于Jackson实现的序列化器,序列化Java对象为JSON字符串,反序列化JSON字符串为Java对象。使用JSON字符串存储,结构清晰,容易阅读,存储的字节少,速度快,并且支持规则配置。

可以看到内部维护了一个ObjectMapper

public class Jackson2JsonRedisSerializer implements RedisSerializer {      private ObjectMapper mapper;          private final JacksonObjectReader reader;          private final JacksonObjectWriter writer; 	 	// 序列化     public T deserialize(@Nullable byte[] bytes) throws SerializationException {         if (SerializationUtils.isEmpty(bytes)) {             return null;         } else {             try {                 return this.reader.read(this.mapper, bytes, this.javaType);             } catch (Exception var3) {                 throw new SerializationException("Could not read JSON: " + var3.getMessage(), var3);             }         }     } 	// 反序列化     public byte[] serialize(@Nullable Object t) throws SerializationException {         if (t == null) {             return SerializationUtils.EMPTY_ARRAY;         } else {             try {                 return this.writer.write(this.mapper, t);             } catch (Exception var3) {                 throw new SerializationException("Could not write JSON: " + var3.getMessage(), var3);             }         }     } } 

4. 案例演示

接下来我们演示如何配置Jackson2JsonRedisSerializer

4.1 创建 RedisTemplate

首先需要创建RedisTemplate并注册到容器中,指定泛型为,因为Redis是一个键值存储数据库,键直接使用字符串即可,而值一般都是多种类型的,统一用Object表示。

    @Bean("redisTemplate")     public RedisTemplate redisTemplate(RedisConnectionFactory factory) {         RedisTemplate redisTemplate = new RedisTemplate<>();         redisTemplate.setConnectionFactory(factory); // 设置连接工厂 } 

4.2 创建 ObjectMapper

创建ObjectMapper对象,可以根据需求进行相应的配置:

        // 创建 ObjectMapper         ObjectMapper objectMapper = Jackson2ObjectMapperBuilder                 .json()                 .serializationInclusion(JsonInclude.Include.NON_NULL) // 不为 null 才序列化                 .visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) // 可见性,只序列化任意修饰符的字段                 .indentOutput(true) // 美化格式                 .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) // 关闭某个特征                 .build();         // 启用自动包含类型信息,用于反序列化时重建对象的实际类型         objectMapper.activateDefaultTyping(                 objectMapper.getPolymorphicTypeValidator(),  //  验证器,用于验证实际要反序列化的子类型是否有效                 ObjectMapper.DefaultTyping.NON_FINAL, // 定义哪些类型的对象需要添加额外的类型信息,NON_FINAL:非 final类都会包含                 JsonTypeInfo.As.PROPERTY); // 类型信息的包含方式 PROPERTY:类型信息作为JSON对象的一个属性 

4.3 创建 Jackson2JsonRedisSerializer

创建Jackson2JsonRedisSerializer,并设置创建好的ObjectMapper对象:

        // 创建 Jackson2JsonRedisSerializer         Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);  

4.4 设置序列化器

设置Key的序列化器为StringRedisSerializer,设置值的序列化器为Jackson2JsonRedisSerializer

        // 设置键值的序列化器         redisTemplate.setKeySerializer(new StringRedisSerializer());         redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);          // 设置Hash 键值的序列化器         redisTemplate.setHashKeySerializer(new StringRedisSerializer());         redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 

最终代码如下所示:

@Configuration public class RedisConfig {      @Bean("redisTemplate")     public RedisTemplate redisTemplate(RedisConnectionFactory factory) {         // 创建 RedisTemplate         RedisTemplate redisTemplate = new RedisTemplate<>();         redisTemplate.setConnectionFactory(factory); // 设置连接工厂          // 创建 ObjectMapper         ObjectMapper objectMapper = Jackson2ObjectMapperBuilder                 .json()                 .serializationInclusion(JsonInclude.Include.NON_NULL) // 不为 null 才序列化                 .visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) // 可见性,只序列化任意修饰符的字段                 .indentOutput(true) // 美化格式                 .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) // 关闭某个特征                 .build();         // 启用自动包含类型信息,用于反序列化时重建对象的实际类型         objectMapper.activateDefaultTyping(                 objectMapper.getPolymorphicTypeValidator(),  //  验证器,用于验证实际要反序列化的子类型是否有效                 ObjectMapper.DefaultTyping.NON_FINAL, // 定义哪些类型的对象需要添加额外的类型信息,NON_FINAL:非 final类都会包含                 JsonTypeInfo.As.PROPERTY); // 类型信息的包含方式 PROPERTY:类型信息作为JSON对象的一个属性          // 创建 Jackson2JsonRedisSerializer         Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);          // 设置键值的序列化器         redisTemplate.setKeySerializer(new StringRedisSerializer());         redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);          // 设置Hash 键值的序列化器         redisTemplate.setHashKeySerializer(new StringRedisSerializer());         redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);         return redisTemplate;     }     } }  

4.5 测试

注入RedisTemplate并执行存取操作:

    @Autowired     RedisTemplate redisTemplate; 

查看Redis
在这里插入图片描述

相关内容

热门资讯

绝活儿辅助!广西老友玩老是输怎... 绝活儿辅助!广西老友玩老是输怎么办(辅助挂)都是真的有辅助app(讲解有挂)在进入广西老友玩老是输怎...
法门辅助!福建13水插件(辅助... 法门辅助!福建13水插件(辅助挂)一贯是有辅助技巧(有挂技术)1、许多玩家不知道福建13水插件辅助怎...
办法辅助!潮友会app下载官方... 办法辅助!潮友会app下载官方辅助器(辅助挂)真是真的是有辅助app(有挂教程)该软件可以轻松地帮助...
妙招辅助!邯郸胡乐挂辅助(辅助... 妙招辅助!邯郸胡乐挂辅助(辅助挂)好像存在有辅助插件(有挂方略)1、上手简单,内置详细流程视频教学,...
教程书辅助!乐酷辅助(辅助挂)... 教程书辅助!乐酷辅助(辅助挂)其实存在有辅助脚本(有挂细节)乐酷辅助能透视中分为三种模型:乐酷辅助模...
学习辅助!决战卡五星辅助(辅助... 学习辅助!决战卡五星辅助(辅助挂)本来真的是有辅助软件(有人有挂)学习辅助!决战卡五星辅助(辅助挂)...
绝活辅助!边锋嘉兴麻将辅助器(... 绝活辅助!边锋嘉兴麻将辅助器(辅助挂)真是真的有辅助神器(新版有挂)1、边锋嘉兴麻将辅助器公共底牌简...
举措辅助!枫叶辅助器(辅助挂)... 举措辅助!枫叶辅助器(辅助挂)本来存在有辅助技巧(竟然有挂)1、下载好枫叶辅助器正确养号方法之后点击...
讲义辅助!点我达辅助(辅助挂)... 讲义辅助!点我达辅助(辅助挂)一直存在有辅助技巧(有人有挂)1、点我达辅助辅助器安装包、点我达辅助辅...
模块辅助!威信茶馆有挂的吗(辅... 模块辅助!威信茶馆有挂的吗(辅助挂)一直真的是有辅助脚本(揭秘有挂)1、玩家可以在威信茶馆有挂的吗线...