Jackson 2.x 系列【29】Spring Boot 集成之 Redis 序列化/反序列化

server/2024/9/23 7:34:00/

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

本系列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<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> 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<T> {// 静态方法,直接返回不同类型的 RedisSerializer 实例static RedisSerializer<Object> java() {return java((ClassLoader)null);}static RedisSerializer<Object> java(@Nullable ClassLoader classLoader) {return new JdkSerializationRedisSerializer(classLoader);}static RedisSerializer<Object> json() {return new GenericJackson2JsonRedisSerializer();}static RedisSerializer<String> string() {return StringRedisSerializer.UTF_8;}static RedisSerializer<byte[]> byteArray() {return ByteArrayRedisSerializer.INSTANCE;}// 序列化@Nullablebyte[] serialize(@Nullable T value) throws SerializationException;// 反序列化@NullableT 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进行存取操作:

    @AutowiredRedisTemplate<Object,Object> redisTemplate;@Testvoid testRedisTemplate() {UserVO userVO = new UserVO();userVO.setId(1699657986705854464L);userVO.setUsername("jack");userVO.setBirthday(new Date());List<String> 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<T> implements RedisSerializer<T> {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并注册到容器中,指定泛型为<String, Object>,因为Redis是一个键值存储数据库,键直接使用字符串即可,而值一般都是多种类型的,统一用Object表示。

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

4.2 创建 ObjectMapper

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

        // 创建 ObjectMapperObjectMapper 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对象:

        // 创建 Jackson2JsonRedisSerializerJackson2JsonRedisSerializer<Object> 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<String, Object> redisTemplate(RedisConnectionFactory factory) {// 创建 RedisTemplateRedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(factory); // 设置连接工厂// 创建 ObjectMapperObjectMapper 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对象的一个属性// 创建 Jackson2JsonRedisSerializerJackson2JsonRedisSerializer<Object> 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并执行存取操作:

    @AutowiredRedisTemplate<String,Object> redisTemplate;

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


http://www.ppmy.cn/server/6929.html

相关文章

docker-compose 安装MongoDB续:创建用户及赋权

文章目录 1. 问题描述2. 分析2.1 admin2.2 config2.3 local 3. 如何连接3.解决 1. 问题描述 在这一篇使用docker-compose创建MongoDB环境的笔记里&#xff0c;我们创建了数据库&#xff0c;但是似乎没有办法使用如Robo 3T这样的工具去连接数据库。连接的时候会返回这样的错误&…

头歌实训作业答案c++

由于“头歌实训作业答案C”这个表述可能指的是某个特定课程或机构的C编程作业答案&#xff0c;通常这类作业答案不会公开分享&#xff0c;因为这涉及到版权和学术诚信的问题。但我可以提供一些C编程的通用指导和资源&#xff0c;帮助你完成实训作业。 ### C编程基础 1. **变量…

Redis详解和Spring Data Redis应用

注意事项 如何快速进入命令行窗口什么是配置类 Redis简介 Redis是一个开源的使用ANSI C语言编写的、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;并提供多种语言的API。它通常被称为数据结构服务器&#xff0c;因为值&#xff08;value&#xff09…

排序之插入排序:从斗地主到插入排序

目录 1.斗地主如何摸牌 2.从摸牌想到插入排序 3.完成插入排序 4.结束语 1.斗地主如何摸牌 不知道各位是否玩过几乎人人都玩过的斗地主游戏呢&#xff1f;相必各位或多或少都玩过一点&#xff0c;再没玩过也看别人打过。今天博主就将从这个游戏为大家讲解我们的插入排序。 在…

MongoDB的CURD(增删改查操作)

读者大大们好呀&#xff01;&#xff01;!☀️☀️☀️ &#x1f525; 欢迎来到我的博客 &#x1f440;期待大大的关注哦❗️❗️❗️ &#x1f680;欢迎收看我的主页文章➡️寻至善的主页 ✈️如果喜欢这篇文章的话 &#x1f64f;大大们可以动动发财的小手&#x1f449;&#…

实习学习内容-Lua语法

Lua是一种轻量级的脚本语言&#xff0c;以其简单、灵活和高效的特点被广泛应用于嵌入式系统、游戏开发和服务器端编程中。Lua语言的设计目标是为了嵌入应用程序中&#xff0c;提供灵活的扩展和定制功能。下面&#xff0c;我将简要介绍Lua的基本语法和特点。 基本语法 变量和类…

什么是集成测试?它和系统测试的区别是什么? 操作方法来了

01 什么是集成测试&#xff1f; 集成测试是软件测试的一种方法&#xff0c;用于测试不同的软件模块之间的交互和协作是否正常。集成测试的主要目的是确保不同的软件模块能够无缝协作&#xff0c;形成一个完整的软件系统&#xff0c;并且能够满足系统的需求和规格。 在集成测试…

py php shell 等等 使用脚本 处理文本 名字定义

目录 需要处理的文本处理完成的文本 需要处理的文本 一般情况下&#xff0c;处理文本的程序或函数通常会使用一些描述性的名称来指代文本。以下是一些常见的命名建议&#xff1a; text: 如果你的程序或函数接受单个文本作为输入&#xff0c;并对其进行处理&#xff0c;那么可…