SpringBoot + Redis +SpringSession 缓存之实战
前言
前几天,从师兄那儿了解到EhCache
是进程内的缓存框架,虽然它已经提供了集群环境下的缓存同步策略,这种同步仍然需要消耗一定时间的,就是从某种程度上讲短暂的缓存不一致依旧存在。
所以,我就选择了集中式缓存,在 SpringBoot 工程中使用 Redis 进行缓存。
个人参考案例
个人博客 : https://zggdczfr.cn/
个人参考案例(如果认可的话,麻烦给颗star) : https://github.com/FunriLy/springboot-study/tree/master/%E6%A1%88%E4%BE%8B10
(一)Spring Boot + Redis
1. 安装 Redis
Redis 原本是不支持在 Window 操作系统安装运行的,但后来有了 Window 支持,放上链接(具体安装百度一下就有): https://github.com/MSOpenTech/redis/releases
注意:建议使用 2.8+ 以上Reids版本,不然会与 SpringSeeeion 产生冲突!
2. 添加依赖
新建一个SpringBoot工程,配置MyBatis+Druid。在pom.xml文件中添加Redis缓存支持。
1 2 3 4 5 6 7 8 9 10 | <!-- 缓存依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <!-- spring boot redis 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency> |
3. application.properties 配置
有关于 Redis 配置参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Redis 配置(默认配置) # Redis 数据库索引(默认为 0 ) spring.redis.database= 0 # Redis 服务器地址 spring.redis.host=localhost # Redis 服务器端口 spring.redis.port= 6379 # Redis 服务器密码(默认为空) spring.redis.password= # 连接池最大连接数(使用负值表示没有限制) spring.redis.pool.max-active= 8 # 连接池中的最大空闲连接 spring.redis.pool.max-idle= 8 # 连接池中的最小空闲连接 spring.redis.pool.min-idle= 0 # 连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.pool.max-wait=- 1 # 设置连接超时 spring.redis.timeout= 0 |
4. 关于 SpringBoot 缓存注解
在支持 Spring Cache 的环境下,
@EnableCaching
: 开启SpringBoot缓存策略,放在启动主类。@CacheConfig(cacheNames = "XXX")
: 设置一个名为”XXX”的缓存空间。@Cacheable
: Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CacheEvict
: 清除缓存。@CachePut
:@CachePut
也可以声明一个方法支持缓存功能。使用@CachePut
标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
5. 添加 Redis 配置类
重要参考资料 : http://www.jianshu.com/p/a2ab17707eff
这个类主要是为Redis添加序列化工具,这一点 SpringBoot 并没有帮我们封装好(或者我没有找到)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { @Value ( "${spring.redis.host}" ) private String host; @Value ( "${spring.redis.port}" ) private int port; @Value ( "${spring.redis.timeout}" ) private int timeout; @Bean public KeyGenerator wiselyKeyGenerator(){ return new KeyGenerator() { @Override public Object generate(Object o, Method method, Object... objects) { StringBuilder sb = new StringBuilder(); sb.append(o.getClass().getName()); sb.append(method.getName()); for (Object obj : objects){ sb.append(obj.toString()); } return sb.toString(); } }; } @Bean public JedisConnectionFactory redisConnectionFactory(){ JedisConnectionFactory factory = new JedisConnectionFactory(); factory.setHostName(host); factory.setPort(port); factory.setTimeout(timeout); //设置连接超时 return factory; } @Bean public CacheManager cacheManager(RedisTemplate redisTemplate){ RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); cacheManager.setDefaultExpiration( 10 ); //设置 key-value 超时时间 return cacheManager; } @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){ StringRedisTemplate template = new StringRedisTemplate(factory); setSerializer(template); //设置序列化工具,就不必实现Serializable接口 template.afterPropertiesSet(); return template; } private void setSerializer(StringRedisTemplate template){ Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object. class ); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setValueSerializer(jackson2JsonRedisSerializer); } } |
其它
其他代码就不累赘贴出来了,直接参考一下我的Github仓库 : https://github.com/FunriLy/springboot-study/tree/master/%E6%A1%88%E4%BE%8B10
启动工程后,访问 http://localhost:8080/redis ,我们可以在控制台看到以下结果:
1 2 3 4 5 6 | 没有走缓存!8b10aba26bd5402bbdad2584d8452f1f User{uuid= '8b10aba26bd5402bbdad2584d8452f1f' , name= '张三' , age= 20 } User{uuid= '8b10aba26bd5402bbdad2584d8452f1f' , name= '张三' , age= 20 } ====== 修改 Redis 缓存数据 ====== User{uuid= '8b10aba26bd5402bbdad2584d8452f1f' , name= '李四' , age= 18 } User{uuid= '8b10aba26bd5402bbdad2584d8452f1f' , name= '李四' , age= 18 } |
补充:若还是不太了解的话,可以查看一下我的上一篇博客spring boot学习(十三)SpringBoot缓存(EhCache 2.x 篇),里面利用了Log4j的debug模式详细打印了执行过的SQL语句,或者利用Druid控制台来查看SQL语句的执行情况。
(二)Spring Session
分布式系统中,sessiong共享有很多的解决方案,其中托管到缓存中应该是最常用的方案之一。
SpringSession 原理
@EnableRedisHttpSession
这个注解创建了一个名为 springSessionRepositoryFilter 的 bean,负责替换 httpSession,同时由 redis 提供缓存支持。
maxInactiveIntervalInSeconds
:设置Session失效时间。使用Redis Session之后,原Boot的server.session.timeout属性不再生效。
1. 添加 SpringSession 配置类
1 2 3 4 5 | @Configuration @EnableRedisHttpSession (maxInactiveIntervalInSeconds = 86400 * 30 ) public class HttpSessionConfig { // 默认无配置 } |
2. 添加验证的URL接口
1 2 3 4 5 6 7 8 9 10 | @Value ( "${server.port}" ) String port; @RequestMapping (value = "/session" , method = RequestMethod.GET) public Object getSession(HttpServletRequest request){ Map<String, Object> map = new HashMap<String, Object>(); map.put( "SessionId" , request.getSession().getId()); map.put( "ServerPort" , "服务端口号为 " +port); return map; } |
同时启动两个相同的工程(比如:8080端口与9090端口),访问 http://localhost:8080/session 与 http://localhost:9090/session
我们可以得到以下结果:
1 2 3 | { "SessionId" : "01f353e1-5cd3-4fbd-a5d0-9a73e17dcec2" , "ServerPort" : "服务端口号为 8080" } { "SessionId" : "01f353e1-5cd3-4fbd-a5d0-9a73e17dcec2" , "ServerPort" : "服务端口号为 9090" } |
结果中的SessionId是一致的,却是由两个不同项目工程来提供服务。这样子,SpringSession 利用拦截器 Filter 帮我们在每个请求前进行了同步设置,达到了分布式系统中 session 共享。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具