有道无术,术尚可求,有术无道,止于术。
本系列Jackson 版本 2.17.0
本系列Spring Boot 版本 3.2.4
源码地址:https://gitee.com/pearl-organization/study-jaskson-demo
文章目录
-
- [1. 前言](#1. 前言)
- [2. RedisTemplate](#2. RedisTemplate)
- [3. RedisSerializer](#3. RedisSerializer)
-
- [3.1 JdkSerializationRedisSerializer](#3.1 JdkSerializationRedisSerializer)
- [3.2 Jackson2JsonRedisSerializer](#3.2 Jackson2JsonRedisSerializer)
- [4. 案例演示](#4. 案例演示)
-
- [4.1 创建 RedisTemplate](#4.1 创建 RedisTemplate)
- [4.2 创建 ObjectMapper](#4.2 创建 ObjectMapper)
- [4.3 创建 Jackson2JsonRedisSerializer](#4.3 创建 Jackson2JsonRedisSerializer)
- [4.4 设置序列化器](#4.4 设置序列化器)
- [4.5 测试](#4.5 测试)
1. 前言
Redis
是一个常用的高性能非关系型内存数据库,接下来我们学习在Spring Boot
中使用Redis
时,集成基于Jackson
的序列化/反序列化。
2. RedisTemplate
RedisTemplate
是在Spring Boot
环境中和Redis
打交道的一个模板类,简化了与Redis
数据库的交互过程,我们可以更加便捷地进行Redis
的各种操作,如数据存取、异常处理及序列化等。
StringRedisTemplate
是RedisTemplate
的一个扩展,由于大多数针对Redis
的操作都是基于字符串的,所以提供了一个专用的类来处理这些操作。
在Spring Boot
自动配置中,已经帮我们注册了这个两个对象,使用时直接注入即可:
java
@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
的序列化/反序列化,定义了相应的操作方法:
java
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;
}
// 序列化
@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
接口,存储的数据是不可读的。
核心方法如下:
java
// 反序列化
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
进行存取操作:
java
@Autowired
RedisTemplate<Object,Object> redisTemplate;
@Test
void 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
:
java
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
表示。
java
@Bean("redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory); // 设置连接工厂
}
4.2 创建 ObjectMapper
创建ObjectMapper
对象,可以根据需求进行相应的配置:
java
// 创建 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
对象:
java
// 创建 Jackson2JsonRedisSerializer
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
4.4 设置序列化器
设置Key
的序列化器为StringRedisSerializer
,设置值的序列化器为Jackson2JsonRedisSerializer
:
java
// 设置键值的序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// 设置Hash 键值的序列化器
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
最终代码如下所示:
java
@Configuration
public class RedisConfig {
@Bean("redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// 创建 RedisTemplate
RedisTemplate<String, Object> 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<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
并执行存取操作:
java
@Autowired
RedisTemplate<String,Object> redisTemplate;
查看Redis
: