Spring Boot 结合 Redis 序列化配置的一些问题
前言
最近在学习Spring Boot结合Redis时看了一些网上的教程,发现这些教程要么比较老,要么不知道从哪抄得,运行起来有问题。这里分享一下我最新学到的写法
默认情况下,Spring 为我们提供了一个 RedisTemplate 来进行对 Redis 的操作,但是 RedisTemplate 默认配置的是使用Java本机序列化。
这种序列化方式,对于操作字符串或数字来说,用起来还行,但是如果要对对象操作,就不是那么的方便了。
所以我们需要配置合适的序列化方式。在 Spring 官方的文档中,官方也建议了我们使用其他的方式来进行序列化。比如JSON

https://docs.spring.io/spring-data/redis/docs/2.2.5.RELEASE/reference/html/#redis:serializer
配置类
配置 Jackson2JsonRedisSerializer 序列化策略
下面就开始自动配置类的书写
我使用的是 Jackson2JsonRedisSerializer 来对对象进行序列化,所以首先需要一个方法,来配置 Jackson2JsonRedisSerializer 序列化策略
private Jackson2JsonRedisSerializer<Object> serializer() {
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return jackson2JsonRedisSerializer;
}
这里要注意的是
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
这一句,这一句非常的重要,作用是序列化时将对象全类名一起保存下来
设置之后的序列化结果如下:
[
"com.buguagaoshu.redis.model.User",
{
"name": "1",
"age": "11",
"message": "牛逼"
}
]
不设置的话,序列化结果如下,将无法反序列化
{
"name": "1",
"age": "11",
"message": "牛逼"
}
一开始,我在网上搜了一下,发现大多数教程因为时间的原因,这一句用的是
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
但当我把这段代码写入的时候,发现Idea提示我

着是一个过时的方法,由于我当时并不知道这句话的意思,就把这段代码注释了,觉得可能没什么用,但注释后在向Redis里写数据的时候,数据会变成


导致数据无法反序列化。
最后我查看了这个方法的源码,找到了


通过注释,我得到了这段代码的最新写法。
也明白了这段代码的作用。
配置 RedisTemplate
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
redisTemplate.setValueSerializer(serializer()); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 使用StringRedisSerializer来序列化和反序列化redis的key值
redisTemplate.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式
redisTemplate.setHashKeySerializer(stringRedisSerializer);
// hash的value序列化方式采用jackson
redisTemplate.setHashValueSerializer(serializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
这里就没有什么需要注意的了,按照自己的需求,来配置序列化的方式
配置缓存策略
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
// 配置序列化(解决乱码的问题)
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
// 缓存有效期
.entryTtl(timeToLive)
// 使用StringRedisSerializer来序列化和反序列化redis的key值
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer()))
// 禁用空值
.disableCachingNullValues(); return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
测试代码
@SpringBootTest
public class RedisApplicationTests {
@Autowired
private RedisTemplate<String, Object> redisTemplate; @Test
void contextLoads() throws Exception {
User user = new User();
user.setName("15");
user.setAge(20);
user.setMessage("牛逼");
redisTemplate.opsForValue().set(user.getName(), user);
User getUser = (User) redisTemplate.opsForValue().get(user.getName());
System.out.println(getUser);
System.out.println(getUser.getMessage());
} }
再来查看Redis中的数据

数据正常,并且系统也能正常的反序列化了。
完整代码
package com.buguagaoshu.redis.config; import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
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.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer; import java.time.Duration; /**
* @author Pu Zhiwei {@literal puzhiweipuzhiwei@foxmail.com}
* create 2020-03-17 21:08
* 继承 CachingConfigurerSupport,为了自定义生成 KEY 的策略。可以不继承。
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Value("${spring.cache.redis.time-to-live}")
private Duration timeToLive = Duration.ZERO; /**
* 配置Jackson2JsonRedisSerializer序列化策略
* */
private Jackson2JsonRedisSerializer<Object> serializer() {
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper(); // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return jackson2JsonRedisSerializer;
} @Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
redisTemplate.setValueSerializer(serializer()); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 使用StringRedisSerializer来序列化和反序列化redis的key值
redisTemplate.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式
redisTemplate.setHashKeySerializer(stringRedisSerializer);
// hash的value序列化方式采用jackson
redisTemplate.setHashValueSerializer(serializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
} @Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
// 配置序列化(解决乱码的问题)
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
// 缓存有效期
.entryTtl(timeToLive)
// 使用StringRedisSerializer来序列化和反序列化redis的key值
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer()))
// 禁用空值
.disableCachingNullValues(); return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
}
Spring Boot 结合 Redis 序列化配置的一些问题的更多相关文章
- Spring Boot自定义Redis缓存配置,保存value格式JSON字符串
Spring Boot自定义Redis缓存,保存格式JSON字符串 部分内容转自 https://blog.csdn.net/caojidasabi/article/details/83059642 ...
- Spring Boot + Mybatis + Redis二级缓存开发指南
Spring Boot + Mybatis + Redis二级缓存开发指南 背景 Spring-Boot因其提供了各种开箱即用的插件,使得它成为了当今最为主流的Java Web开发框架之一.Mybat ...
- (35)Spring Boot集成Redis实现缓存机制【从零开始学Spring Boot】
[本文章是否对你有用以及是否有好的建议,请留言] 本文章牵涉到的技术点比较多:Spring Data JPA.Redis.Spring MVC,Spirng Cache,所以在看这篇文章的时候,需要对 ...
- Spring Boot 2.X(六):Spring Boot 集成Redis
Redis 简介 什么是 Redis Redis 是目前使用的非常广泛的免费开源内存数据库,是一个高性能的 key-value 数据库. Redis 与其他 key-value 缓存(如 Memcac ...
- Spring Boot2 系列教程(二十六)Spring Boot 整合 Redis
在 Redis 出现之前,我们的缓存框架各种各样,有了 Redis ,缓存方案基本上都统一了,关于 Redis,松哥之前有一个系列教程,尚不了解 Redis 的小伙伴可以参考这个教程: Redis 教 ...
- 【spring boot】【redis】spring boot基于redis的LUA脚本 实现分布式锁
spring boot基于redis的LUA脚本 实现分布式锁[都是基于redis单点下] 一.spring boot 1.5.X 基于redis 的 lua脚本实现分布式锁 1.pom.xml &l ...
- Spring Boot与Redis的集成
Redis是一个完全开源免费的.遵守BSD协议的.内存中的数据结构存储,它既可以作为数据库,也可以作为缓存和消息代理.因其性能优异等优势,目前已被很多企业所使用,但通常在企业中我们会将其作为缓存来使用 ...
- Spring Boot学习笔记——Spring Boot与Redis的集成
一.添加Redis缓存 1.添加Redis起步依赖 在pom.xml中添加Spring Boot支持Redis的依赖配置,具体如下: <dependency> <groupId> ...
- Spring Boot 整合 Redis 和 JavaMailSender 实现邮箱注册功能
Spring Boot 整合 Redis 和 JavaMailSender 实现邮箱注册功能 开篇 现在的网站基本都有邮件注册功能,毕竟可以通过邮件定期的给用户发送一些 垃圾邮件 精选推荐
随机推荐
- Ajax 请求参数过多导致 400 错误 and BCryptPasswordEncoder 加密判断
2019/06/19 先分享一种密码加密方式: Spring Security 提供了 BCryptPasswordEncoder类, 实现Spring的PasswordEncoder接口使用BCry ...
- springmvc拦截器入门及其执行顺序源码分析
springmvc拦截器是偶尔会用到的一个功能,本案例来演示一个较简单的springmvc拦截器的使用,并通过源码来分析拦截器的执行顺序的控制.具体操作步骤为:1.maven项目引入spring依赖2 ...
- 饿了么vue实现学习笔记
技术栈:vue2 + vuex + vue-router + webpack + ES6/7 + fetch + sass + flex + svg以功能实现着手学习1. 定位功能 home.vue ...
- Java Servlet XML文件配置
- Servlet与JSP概念理解
Servlet是用Java编写的服务端程序.需要部署到servlet容器上才能运行,tomcat 就是一个servlet容器. 1.Servlet的生命周期 客户端请求该 Servlet --> ...
- python os.path 模块常用方法
代码: import os apath = os.path.abspath(__file__) # 绝对路径 dirname = os.path.dirname(apath) basename = o ...
- PHP RFI 的小tip
有关PHP include的帖子网上已经很多了,wooyun的知识库里面也有一篇总结的很好的文章,传送门:http://drops.wooyun.org/tips/3827,今晚在看书的时候看到RFI ...
- 牛客网剑指offer第21题——判断出栈序列是否是入栈序列
题目: 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈 ...
- flask 中文乱码
返回的json数据中包含中文,但前端显示乱码,添加了 app.config['JSON_AS_ASCII'] = False仍然没有解决, app.config['JSONIFY_MIMETYPE'] ...
- NIO-EPollSelectorIpml源码分析
目录 NIO-EPollSelectorIpml源码分析 目录 前言 初始化EPollSelectorProvider 创建EPollSelectorImpl EPollSelectorImpl结构 ...