【Spring Boot 3 + fastjson2】更改RedisTemplate的序列化策略
pom依赖</</</</</</</</</</</</</</</</</</</</</</</</
环境:jdk17、Spring Boot 3.1.3、fastjson2 2.0.41
pom依赖
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>3.1.3</spring-boot.version>
<fastjson2.version>2.0.41</fastjson2.version>
<properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-extension-spring6</artifactId>
<version>${fastjson2.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Jackson2Json
在查找资料的过程中,RedisTemplate的序列化策略大部分是用jackson去实现的,这里我也在这里实现以下
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.jsontype.impl.LaissezFaireSubTypeValidator;
import jakarta.annotation.Resource;
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.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisTemplateConfig {
@Resource
private RedisConnectionFactory redisConnectionFactory;
@Bean
public RedisTemplate<String, Object> redisTemplate() {
// 自定义 String Object
RedisTemplate<String, Object> template = new RedisTemplate<>();
// ObjectMapper 转译
ObjectMapper objectMapper = createObjectMapper();
// Json 序列化配置
Jackson2JsonRedisSerializer<Object> objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
// String 的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key 采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash 的key也采用 String 的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value 序列化方式采用 jackson
template.setValueSerializer(objectJackson2JsonRedisSerializer);
// hash 的 value 采用 jackson
template.setHashValueSerializer(objectJackson2JsonRedisSerializer);
template.setConnectionFactory(redisConnectionFactory);
template.afterPropertiesSet();
return template;
}
private ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.WRAPPER_ARRAY
);
return mapper;
}
}
如果key不采用stringRedisSerializer方式的话,存储的key会有双引号(“”)而且无法通过key去get到value
Tips:
new Jackson2JsonRedisSerializer<>(objectMapper, Object.class)
这个方法是3.0才有的,不是3.0的话使用objectJackson2JsonRedisSerializer.setObjectMapper(objectMapper)
才行,到3.0objectJackson2JsonRedisSerializer.setObjectMapper(objectMapper)
这个方法已经过时了,所以采用new Jackson2JsonRedisSerializer<>(objectMapper, Object.class)
这个方法比较好。
fastjson2
查看Jackson2JsonRedisSerializer
的源码知道这个类是实现了RedisSerializer<>
的,所以我们也要实现。
先定义一个Fastjson2RedisSerializer
并实现RedisSerializer<>
:
public class FastJson2RedisSerializer<T> implements RedisSerializer<T> {}
然后去实现方法,这里加快速度,直接展示成品
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.Filter;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
public class FastJson2RedisSerializer<T> implements RedisSerializer<T> {
static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(
// 按需加上需要支持自动类型的类名前缀,范围越小越安全
"com.***.***"
);
private final Class<T> clazz;
public FastJson2RedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
return JSON.toJSONBytes(t, JSONWriter.Feature.WriteClassName);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (ArrayUtils.isEmpty(bytes)) {
return null;
}
return JSON.parseObject(bytes, clazz, AUTO_TYPE_FILTER);
}
}
然后再去配置类中实现我们的fastjson2的序列化配置
import jakarta.annotation.Resource;
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.serializer.StringRedisSerializer;
@Configuration
public class RedisTemplateConfig {
@Resource
private RedisConnectionFactory redisConnectionFactory;
@Bean
public RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
FastJson2RedisSerializer<Object> fastJson2RedisSerializer = new FastJson2RedisSerializer<>(Object.class);
StringRedisSerializer serializer = new StringRedisSerializer();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(serializer);
template.setHashKeySerializer(serializer);
template.setValueSerializer(fastJson2RedisSerializer);
template.setHashValueSerializer(fastJson2RedisSerializer);
template.afterPropertiesSet();
return template;
}
}
优化
FastJson2RedisSerializer
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.Filter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.util.Objects;
@Slf4j
public class FastJson2RedisSerializer<T> implements RedisSerializer<T> {
static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(
// 按需加上需要支持自动类型的类名前缀,范围越小越安全
"com.***.***"
);
private final Class<T> clazz;
public FastJson2RedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException {
if (Objects.isNull(t)) {
return new byte[0];
}
try {
return JSON.toJSONBytes(t, JSONWriter.Feature.WriteClassName);
} catch (Exception e) {
log.error("Fastjson2 序列化错误:{}", e.getMessage());
throw new SerializationException("无法序列化: " + e.getMessage(), e);
}
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (ArrayUtils.isEmpty(bytes)) {
return null;
}
try {
return JSON.parseObject(bytes, clazz, AUTO_TYPE_FILTER);
} catch (Exception e) {
log.error("Fastjson2 反序列化错误:{}", e.getMessage());
throw new SerializationException("无法反序列化: " + e.getMessage(), e);
}
}
}
更多推荐
所有评论(0)