Spring Boot 3 整合 Spring Cache 与 Redis 缓存实战

news/2024/12/19 22:45:54/

🚀 作者主页: 有来技术
🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot
🌺 仓库主页: Gitee 💫 Github 💫 GitCode
💖 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请纠正!

目录

  • 什么是 Spring Cache?
  • Spring Cache 常用 API
    • @Cacheable
    • @CacheEvict
    • @CachePut
    • @Caching
  • Spring Boot 整合 Spring Cache (Redis 缓存)
    • 项目依赖 pom.xml
    • 项目配置 application.yml
    • 自动装配配置类 RedisCacheConfig
  • Spring Boot 路由缓存实战
    • 获取路由数据缓存
    • 更新路由缓存失效
  • Spring Cache 问题整理
    • @Cacheable 缓存的 key 双冒号
  • 结语
  • 开源项目

什么是 Spring Cache?

Spring Cache是Spring框架提供的一层缓存抽象,旨在简化应用程序中的缓存管理。通过使用Spring Cache,开发者能够在方法级别方便地定义缓存策略,提高应用性能、响应速度,并减轻底层数据源的负载。该框架提供一系列注解,如@Cacheable@CacheEvict@CachePut,以及对多种底层缓存实现的支持,如EhCache、Redis等。它为应用程序提供了一种统一、方便、灵活的缓存管理方式,允许开发者通过简单的配置实现复杂的缓存逻辑,同时与Spring框架紧密集成。这种抽象层的存在使得在更改底层缓存框架时更为轻松,同时提供了一致的配置接口和更强大的高级特性。

Spring Cache 常用 API

@Cacheable

@Cacheable 用于标记一个方法的结果应该被缓存。当在该方法被调用时,Spring首先检查缓存中是否已经有了预期的结果,如果有,直接返回缓存中的结果而不执行实际的方法体。

javaCopy code@Cacheable(cacheNames = "exampleCache", key = "'exampleKey'")
public String getCachedData() {// 执行实际的方法体,结果会被缓存
}

@CacheEvict

@CacheEvict 用于标记一个方法在执行后清空缓存。可以指定清空的缓存名称和清空的条件。

javaCopy code@CacheEvict(cacheNames = "exampleCache", key = "'exampleKey'")
public void clearCache() {// 执行实际的方法体,之后清空缓存
}

@CachePut

@CachePut 用于标记一个方法的结果应该被放入缓存,常用于在方法执行后更新缓存。

javaCopy code@CachePut(cacheNames = "exampleCache", key = "'exampleKey'")
public String updateCache() {// 执行实际的方法体,结果会被放入缓存
}

@Caching

@Caching 允许同时应用多个缓存操作注解。

javaCopy code@Caching(evict = {@CacheEvict(cacheNames = "cache1", key = "'key1'"),@CacheEvict(cacheNames = "cache2", key = "'key2'")}
)
public void clearMultipleCaches() {// 执行实际的方法体,清空多个缓存
}

Spring Boot 整合 Spring Cache (Redis 缓存)

完整项目源码:youlai-boot

项目依赖 pom.xml

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>

项目配置 application.yml

spring:data:redis:database: 6host: localhostport: 6379password: 123456timeout: 10slettuce:pool:# 连接池最大连接数 默认8 ,负数表示没有限制max-active: 8# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认-1max-wait: -1# 连接池中的最大空闲连接 默认8max-idle: 8# 连接池中的最小空闲连接 默认0min-idle: 0cache:# 缓存类型 redis、none(不使用缓存)type: redis# 缓存时间(单位:ms)redis:time-to-live: 3600000# 缓存null值,防止缓存穿透cache-null-values: true

自动装配配置类 RedisCacheConfig

package com.youlai.system.config;import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
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.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;/*** Redis 缓存配置** @author haoxr* @since 2023/12/4*/
@EnableCaching
@EnableConfigurationProperties(CacheProperties.class)
@Configuration
public class RedisCacheConfig {/*** 自定义 RedisCacheManager* <p>* 修改 Redis 序列化方式,默认 JdkSerializationRedisSerializer** @param redisConnectionFactory {@link RedisConnectionFactory}* @param cacheProperties        {@link CacheProperties}* @return {@link RedisCacheManager}*/@Beanpublic RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory, CacheProperties cacheProperties){return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)).cacheDefaults(redisCacheConfiguration(cacheProperties)).build();}/*** 自定义 RedisCacheConfiguration** @param cacheProperties {@link CacheProperties}* @return {@link RedisCacheConfiguration}*/@BeanRedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string()));config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));CacheProperties.Redis redisProperties = cacheProperties.getRedis();if (redisProperties.getTimeToLive() != null) {config = config.entryTtl(redisProperties.getTimeToLive());}if (!redisProperties.isCacheNullValues()) {config = config.disableCachingNullValues();}if (!redisProperties.isUseKeyPrefix()) {config = config.disableKeyPrefix();}config = config.computePrefixWith(name -> name + ":");// 覆盖默认key双冒号  CacheKeyPrefix#prefixedreturn config;}}

Spring Boot 路由缓存实战

完整项目源码:youlai-boot

获取路由数据缓存

获取路由列表,通过 @Cacheable 注解,将方法返回的路由列表数据缓存至 Redis。当再次请求时,不再进入方法体,而是直接从 Redis 中读取缓存数据并返回,以提高性能。

    /*** 获取路由列表*/@Override@Cacheable(cacheNames = "menu", key = "'routes'") // cacheNames 为必填项,key 需要使用引号,否则会被识别为变量。public List<RouteVO> listRoutes() {List<RouteBO> menuList = this.baseMapper.listRoutes();return buildRoutes(SystemConstants.ROOT_NODE_ID, menuList);}

更新路由缓存失效

若需要在路由信息更新时使缓存失效,可以使用 @CacheEvict 注解,它用于在方法执行之后(默认)从缓存中移除条目。

    /*** 新增/修改菜单*/@Override@CacheEvict(cacheNames = "menu", key = "'routes'",beforeInvocation = true)public boolean saveMenu(MenuForm menuForm) {String path = menuForm.getPath();MenuTypeEnum menuType = menuForm.getType();// 如果是目录if (menuType == MenuTypeEnum.CATALOG) {if (menuForm.getParentId() == 0 && !path.startsWith("/")) {menuForm.setPath("/" + path); // 一级目录需以 / 开头}menuForm.setComponent("Layout");}// 如果是外链else if (menuType == MenuTypeEnum.EXTLINK) {menuForm.setComponent(null);}SysMenu entity = menuConverter.form2Entity(menuForm);String treePath = generateMenuTreePath(menuForm.getParentId());entity.setTreePath(treePath);return this.saveOrUpdate(entity);}

更新菜单后,Redis 中缓存的路由数据将被清除。再次获取路由时,才会将新的路由数据缓存到 Redis 中。

Spring Cache 问题整理

@Cacheable 缓存的 key 双冒号

默认情况下 @Cacheable 使用双冒号 :: 拼接 cacheNameskey

@Cacheable(cacheNames = "menu", key = "'routes'") 

参考源码 RedisCacheConfiguration#prefixCacheNameWith

如果需要将双冒号改成单个冒号,需要重写 RedisCacheConfiguration#computePrefixWith 方法

config = config.computePrefixWith(name -> name + ":");//覆盖默认key双冒号  CacheKeyPrefix#prefixed

结语

Spring Cache 为 Spring 应用程序提供了简便的缓存管理抽象,通过注解如 @Cacheable@CacheEvict@CachePut,开发者能方便定义缓存策略。整合Spring Boot 与 Redis 缓存实例展示了如何配置、使用Spring Cache,提升应用性能。通过实战演示菜单路由缓存,突显 @Cacheable@CacheEvict 的实际应用,以及解决 @Cacheable 默认key双冒号的问题。

开源项目

  • SpringCloud + Vue3 微服务商城
GithubGitee
后端youlai-mall 🍃youlai-mall 🍃
前端mall-admin🌺mall-admin 🌺
移动端mall-app 🍌mall-app 🍌
  • SpringBoot 3+ Vue3 单体权限管理系统
GithubGitee
后端youlai-boot 🍃youlai-boot 🍃
前端vue3-element-admin 🌺vue3-element-admin 🌺

http://www.ppmy.cn/news/1265895.html

相关文章

对象与对象数组

对象与对象数组 实验介绍 本章节主要介绍对象数组和对象成员。在实际的开发中&#xff0c;对象数组和对象成员是经常使用的&#xff0c;所以首先需要学习对象数组与对象成员的各种使用方法。 提示&#xff1a;为了方便课程讲解&#xff0c;示例代码使用类内定义的方式实现&a…

spring 的概述和入门

​ 我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; …

mysql库名规范

mysql库名的一些规范和建议&#xff1a; 库名以小写字母、数字、下划线组成&#xff0c;不要以数字开头。建议不要超过32个字符&#xff0c;但尽量用简短的名称。因为很多地方用到库名&#xff0c;如果库名太长&#xff0c;容易出错。库名选择有意义的名称&#xff0c;尽量与应…

个人博客搭建保姆级教程-Nginx篇

官方文档 nginx documentation 说明 nginx是我们本次教程使用的http服务器。它能承受很高的并发&#xff0c;并且安装简单&#xff0c;占用内存少。 在服务器篇我们提到了nginx的安装&#xff0c;在发布篇我们简述了该怎么放置我们创建的博客html文档。 在本篇&#xff0c…

Linux中的几个重要指令

关於 Process 处理的指令 1. ps ps 是用来显示目前你的 process 或系统 processes 的状况。 以下列出比较常用的参数: 其选项说明如下: -a 列出包括其他 users 的 process 状况。 -u 显示 user - oriented 的 process 状况 。 -x 显示包括没有 terminal 控制的 process 状…

每日一道算法题 1

借鉴文章&#xff1a;Java-敏感字段加密 - 哔哩哔哩 题目描述 给定一个由多个命令字组成的命令字符串&#xff1b; 1、字符串长度小于等于127字节&#xff0c;只包含大小写字母&#xff0c;数字&#xff0c;下划线和偶数个双引号 2、命令字之间以一个或多个下划线_进行分割…

QT使用SQLite 超详细(增删改查、包括对大量数据快速存储和更新)

QTSQLite 在QT中使用sqlite数据库&#xff0c;有多种使用方法&#xff0c;在这里我只提供几种简单&#xff0c;代码简短的方法&#xff0c;包括一些特殊字符处理。在这里也给大家说明一下&#xff0c;如果你每次要存储的数据量很大&#xff0c;建议使用事务&#xff08;代码中…

一文详解Java单元测试Junit

文章目录 概述、Junit框架快速入门单元测试概述main方法测试的问题junit单元测试框架优点&#xff1a;使用步骤&#xff1a; 使用案例包结构 Junit框架的常见注解测试 概述、Junit框架快速入门 单元测试概述 就是针对最小的功能单元&#xff08;方法&#xff09;&#xff0c;…