SpringBoot 整合缓存Cacheable实战详细使用

2024-06-16 14:38

本文主要是介绍SpringBoot 整合缓存Cacheable实战详细使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

我知道在接口api项目中,频繁的调用接口获取数据,查询数据库是非常耗费资源的,于是就有了缓存技术,可以把一些不常更新,或者经常使用的数据,缓存起来,然后下次再请求时候,就直接从缓存中获取,不需要再去查询数据,这样可以提供程序性能,增加用户体验,也节省服务资源浪费开销,

springboot帮你我们做好了整合,有对应的场景启动器start,我们之间引入使用就好了,帮我们整合了各种缓存

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

简介

缓存介绍

Spring 从 3.1 开始就引入了对 Cache 的支持。定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术。并支持使用 JCache(JSR-107)注解简化我们的开发。

其使用方法和原理都类似于 Spring 对事务管理的支持。Spring Cache 是作用在方法上的,其核心思想是,当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存在缓存中。

Cache 和 CacheManager 接口说明

Cache 接口包含缓存的各种操作集合,你操作缓存就是通过这个接口来操作的。
Cache 接口下 Spring 提供了各种 xxxCache 的实现,比如:RedisCache、EhCache、ConcurrentMapCache

CacheManager 定义了创建、配置、获取、管理和控制多个唯一命名的 Cache。这些 Cache 存在于 CacheManager 的上下文中。

小结

每次调用需要缓存功能的方法时,Spring 会检查指定参数的指定目标方法是否已经被调用过,如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。

使用Spring缓存抽象时我们需要关注以下两点;

  1. 确定方法需要被缓存以及他们的缓存策略
  2. 从缓存中读取之前缓存存储的数据

快速开始

  1. 使用缓存我们需要开启基于注解的缓存,使用 @EnableCaching 标注在 springboot 主启动类上或者配置类上
@SpringBootApplication
@MapperScan(value = {"cn.soboys.kmall.mapper","cn.soboys.kmall.sys.mapper","cn.soboys.kmall.security.mapper"},nameGenerator = UniqueNameGenerator.class)
@ComponentScan(value =  {"cn.soboys.kmall"},nameGenerator = UniqueNameGenerator.class)
@EnableCaching  //开启缓存注解驱动,否则后面使用的缓存都是无效的
public class WebApplication {private static ApplicationContext applicationContext;public static void main(String[] args) {applicationContext =SpringApplication.run(WebApplication.class, args);//displayAllBeans();}/*** 打印所以装载的bean*/public static void displayAllBeans() {String[] allBeanNames = applicationContext.getBeanDefinitionNames();for (String beanName : allBeanNames) {System.out.println(beanName);}}
}

或者配置类

/*** @author kenx* @version 1.0* @date 2021/8/17 15:05* @webSite https://www.soboys.cn/* 自定义缓存配置*/
@Configuration
@Slf4j
@EnableCaching  //开启缓存注解驱动,否则后面使用的缓存都是无效的
public class CacheConfig {//自定义配置类配置keyGenerator@Bean("myKeyGenerator")public KeyGenerator keyGenerator(){return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {return method.getName()+"["+ Arrays.asList(params).toString() +"]";}};}
}
  1. 标注缓存注解在需要缓存的地方使用@Cacheable注解
@CacheConfig(cacheNames = "menuCache",keyGenerator ="myKeyGenerator" )
public interface IMenuService extends IService<Menu> {/*** 获取用户菜单信息** @param username 用户名* @return*/@Cacheable(key = "#username")List<Menu> getUserMenus(String username);
}

@Cacheable注解有如下一些参数我们可以看到他源码

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {@AliasFor("cacheNames")String[] value() default {};@AliasFor("value")String[] cacheNames() default {};String key() default "";String keyGenerator() default "";String cacheManager() default "";String cacheResolver() default "";String condition() default "";String unless() default "";boolean sync() default false;
}

下面介绍一下 @Cacheable 这个注解常用的几个属性:

  1. cacheNames/value :指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定 多个缓存;

  2. key :缓存数据时使用的 key,可以用它来指定。默认是使用方法参数的值。(这个 key 你可以使用 spEL 表达式来编写如 #i d;参数id的值 #a0 #p0 #root.args[0]

  3. keyGenerator :key的生成器;可以自己指定key的生成器的组件id 然后key 和 keyGenerator 二选一使用

  4. cacheManager :可以用来指定缓存管理器。从哪个缓存管理器里面获取缓存。或者cacheResolver指定获取解析器

  5. condition :可以用来指定符合条件的情况下才缓存

condition = "#id>0"
condition = "#a0>1":第一个参数的值》1的时候才进行缓存
  1. unless :否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。当然你也可以获取到结果进行判断。(通过 #result 获取方法结果)
unless = "#result == null"
unless = "#a0==2":如果第一个参数的值是2,结果不缓存;
  1. sync :是否使用异步模式。异步模式的情况下unless不支持 默认是方法执行完,以同步的方式将方法返回的结果存在缓存中

cacheNames/value属性

用来指定缓存组件的名字,将方法的返回结果放在哪个缓存中,可以是数组的方式,支持指定多个缓存

 /*** 获取用户菜单信息** @param username 用户名* @return*/@Cacheable(cacheNames = "menuCache") 或者// @Cacheable(cacheNames = {"menuCache","neCacge"})List<Menu> getUserMenus(String username);

如果只有一个属性,cacheNames可忽略,直接是value属性默认

key

缓存数据时使用的 key。默认使用的是方法参数的值。可以使用 spEL 表达式去编写。

Cache SpEL available metadata

名称位置描述示例
methodNameroot对象当前被调用的方法名#root.methodname
methodroot对象当前被调用的方法#root.method.name
targetroot对象当前被调用的目标对象实例#root.target
targetClassroot对象当前被调用的目标对象的类#root.targetClass
argsroot对象当前被调用的方法的参数列表#root.args[0]
cachesroot对象当前方法调用使用的缓存列表#root.caches[0].name
argumentName执行上下文(avaluation context)当前被调用的方法的参数,如findArtisan(Artisan artisan),可以通过#artsian.id获得参数#artsian.id
result执行上下文(evaluation context)方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false)#result
//key = "#username" 就是参数username@Cacheable(key = "#username" ,cacheNames = "menuCache")
List<Menu> getUserMenus(String username);

keyGenerator

key 的生成器,可以自己指定 key 的生成器,通过这个生成器来生成 key

定义一个@Bean类,将KeyGenerator添加到Spring容器

@Configuration
@Slf4j
@EnableCaching  //开启缓存注解驱动,否则后面使用的缓存都是无效的
public class CacheConfig {//自定义配置类配置keyGenerator@Bean("myKeyGenerator")public KeyGenerator keyGenerator(){return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {return method.getName()+"["+ Arrays.asList(params).toString() +"]";}};}
}

在使用指定自己的@Cacheable(cacheNames = "menuCache",keyGenerator ="myKeyGenerator" )

注意这样放入缓存中的 key 的生成规则就按照你自定义的 keyGenerator 来生成。不过需要注意的是:@Cacheable 的属性,key 和 keyGenerator 使用的时候,一般二选一。

condition

符合条件的情况下才缓存。方法返回的数据要不要缓存,可以做一个动态判断。

 /*** 获取用户菜单信息** @param username 用户名* @return*///判断username 用户名是kenx开头才会被缓存@Cacheable(key = "#username" ,condition = "#username.startsWith('kenx')")List<Menu> getUserMenus(String username);

unless

否定缓存。当 unless 指定的条件为 true ,方法的返回值就不会被缓存。

 /*** 获取用户菜单信息** @param username 用户名* @return*///判断username 用户名是kenx开头不会被缓存@Cacheable(key = "#username" ,condition = "#username.startsWith('kenx')")List<Menu> getUserMenus(String username);

spEL 编写 key

当然我们可以全局去配置,cacheNames,keyGenerator属性通过@CacheConfig注解可以用于抽取缓存的公共配置,然后在类加上就可以,eg:如

//全局配置,下面用到缓存方法,不配置默认使用全局的
@CacheConfig(cacheNames = "menuCache",keyGenerator ="myKeyGenerator" )
public interface IMenuService extends IService<Menu> {/*** 获取用户菜单信息** @param username 用户名* @return*/@CacheablList<Menu> getUserMenus(String username);
}

深入使用

@CachePut

@CachePut注解也是一个用来缓存的注解,不过缓存和@Cacheable有明显的区别是即调用方法,又更新缓存数据,也就是执行方法操作之后再来同步更新缓存,所以这个主键常用于更新操作,也可以用于查询,主键属性和@Cacheable有很多类似的参看 @CachePut源码

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CachePut {@AliasFor("cacheNames")String[] value() default {};@AliasFor("value")String[] cacheNames() default {};String key() default "";String keyGenerator() default "";String cacheManager() default "";String cacheResolver() default "";String condition() default "";String unless() default "";
}
/***  @CachePut:既调用方法,又更新缓存数据;同步更新缓存*  修改了数据,同时更新缓存*/@CachePut(value = {"emp"}, key = "#result.id")public Employee updateEmp(Employee employee){employeeMapper.updateEmp(employee);LOG.info("更新{}号员工数据",employee.getId());return employee;}

@CacheEvict

清空缓存
主要属性:

  1. key:指定要清除的数据
  2. allEntries = true:指定清除这个缓存中所有的数据
  3. beforeInvocation = false:默认代表缓存清除操作是在方法执行之后执行
  4. beforeInvocation = true:代表清除缓存操作是在方法运行之前执行
@CacheEvict(value = {"emp"}, beforeInvocation = true,key="#id")public void deleteEmp(Integer id){employeeMapper.deleteEmpById(id);//int i = 10/0;}

@Caching

@Caching 用于定义复杂的缓存规则,可以集成@Cacheable和 @CachePut

// @Caching 定义复杂的缓存规则@Caching(cacheable = {@Cacheable(/*value={"emp"},*/key = "#lastName")},put = {@CachePut(/*value={"emp"},*/key = "#result.id"),@CachePut(/*value={"emp"},*/key = "#result.email")})public Employee getEmpByLastName(String lastName){return employeeMapper.getEmpByLastName(lastName);}

@CacheConfig

@CacheConfig注解可以用于抽取缓存的公共配置,然后在类加上就可以

//全局配置,下面用到缓存方法,不配置默认使用全局的
@CacheConfig(cacheNames = "menuCache",keyGenerator ="myKeyGenerator" )
public interface IMenuService extends IService<Menu> {/*** 获取用户菜单信息** @param username 用户名* @return*/@Cacheable(key = "#username" )List<Menu> getUserMenus(String username);
}

参考

  1. SpringBoot之缓存使用教程
  2. 缓存入门

这篇关于SpringBoot 整合缓存Cacheable实战详细使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1066723

相关文章

SpringBoot中HTTP连接池的配置与优化

《SpringBoot中HTTP连接池的配置与优化》这篇文章主要为大家详细介绍了SpringBoot中HTTP连接池的配置与优化的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、HTTP连接池的核心价值二、Spring Boot集成方案方案1:Apache HttpCl

使用animation.css库快速实现CSS3旋转动画效果

《使用animation.css库快速实现CSS3旋转动画效果》随着Web技术的不断发展,动画效果已经成为了网页设计中不可或缺的一部分,本文将深入探讨animation.css的工作原理,如何使用以及... 目录1. css3动画技术简介2. animation.css库介绍2.1 animation.cs

Spring Boot项目打包和运行的操作方法

《SpringBoot项目打包和运行的操作方法》SpringBoot应用内嵌了Web服务器,所以基于SpringBoot开发的web应用也可以独立运行,无须部署到其他Web服务器中,下面以打包dem... 目录一、打包为JAR包并运行1.打包为可执行的 JAR 包2.运行 JAR 包二、打包为WAR包并运行

Java进行日期解析与格式化的实现代码

《Java进行日期解析与格式化的实现代码》使用Java搭配ApacheCommonsLang3和Natty库,可以实现灵活高效的日期解析与格式化,本文将通过相关示例为大家讲讲具体的实践操作,需要的可以... 目录一、背景二、依赖介绍1. Apache Commons Lang32. Natty三、核心实现代

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Spring Boot 常用注解整理(最全收藏版)

《SpringBoot常用注解整理(最全收藏版)》本文系统整理了常用的Spring/SpringBoot注解,按照功能分类进行介绍,每个注解都会涵盖其含义、提供来源、应用场景以及代码示例,帮助开发... 目录Spring & Spring Boot 常用注解整理一、Spring Boot 核心注解二、Spr

Python文件操作与IO流的使用方式

《Python文件操作与IO流的使用方式》:本文主要介绍Python文件操作与IO流的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、python文件操作基础1. 打开文件2. 关闭文件二、文件读写操作1.www.chinasem.cn 读取文件2. 写

SpringBoot实现接口数据加解密的三种实战方案

《SpringBoot实现接口数据加解密的三种实战方案》在金融支付、用户隐私信息传输等场景中,接口数据若以明文传输,极易被中间人攻击窃取,SpringBoot提供了多种优雅的加解密实现方案,本文将从原... 目录一、为什么需要接口数据加解密?二、核心加解密算法选择1. 对称加密(AES)2. 非对称加密(R

详解如何在SpringBoot控制器中处理用户数据

《详解如何在SpringBoot控制器中处理用户数据》在SpringBoot应用开发中,控制器(Controller)扮演着至关重要的角色,它负责接收用户请求、处理数据并返回响应,本文将深入浅出地讲解... 目录一、获取请求参数1.1 获取查询参数1.2 获取路径参数二、处理表单提交2.1 处理表单数据三、

PyQt6中QMainWindow组件的使用详解

《PyQt6中QMainWindow组件的使用详解》QMainWindow是PyQt6中用于构建桌面应用程序的基础组件,本文主要介绍了PyQt6中QMainWindow组件的使用,具有一定的参考价值,... 目录1. QMainWindow 组php件概述2. 使用 QMainWindow3. QMainW