【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache管理器的实战开发指南(修正篇)

带你深入分析Spring所提供的缓存Cache管理器的实战开发指南

  • 前提介绍
    • 基于注解的支持
      • @Cacheable
        • cacheable的属性介绍
          • value属性指定Cache名称
          • 使用key属性自定义key
            • 案例分析
            • caches
          • condition属性指定发生的条件
      • @CachePut
        • 使用案例
      • @CacheEvict
        • allEntries属性
        • beforeInvocation属性
      • @Caching
        • @Caching定义如下
        • 使用案例
      • 自定义缓存注解

前提介绍

Spring Cache是基于方法级别的,其核心思想是将调用带有缓存的方法时的参数和返回结果作为键值对存储在缓存中。当下次调用相同参数的方法时,直接从缓存中获取结果,而不再执行该方法。因此,在使用Spring Cache时,需要确保被缓存的方法对于相同的参数具有相同的返回结果。

使用Spring Cache需要进行两个步骤:

  1. 声明需要使用缓存的方法。
  2. 配置Spring对Cache的支持。

与Spring对事务管理的支持类似,Spring对Cache的支持有两种方式:基于注解和基于XML配置。下面我们先来看看基于注解的方式。

基于注解的支持

Spring提供了几个注解来支持Spring Cache,其中核心的注解包括@Cacheable和@CacheEvict。使用@Cacheable标记的方法在执行后,Spring Cache会缓存其返回结果,而使用@CacheEvict标记的方法可以在方法执行前或执行后移除Spring Cache中的某些元素。接下来,我们将详细介绍Spring基于注解对Cache的支持所提供的几个注解。

@Cacheable

@Cacheable注解可以应用于单个方法或整个类。当应用于方法时,该注解表示该方法支持缓存,当应用于类时表示该类的所有方法都支持缓存。被@Cacheable注解标记的方法会在调用后将返回值缓存起来,这样下次使用相同参数调用该方法时,可以直接从缓存中获取结果,无需再次执行该方法,从而提高方法的执行效率。

cacheable的属性介绍

Spring使用键值对来缓存方法的返回值。键用于检索缓存中的结果,而值则是方法的返回结果。Spring支持两种缓存键的策略:默认策略和自定义策略,接下来将对这两种策略进行详细说明。请注意,当一个支持缓存的方法在对象内部被调用时,不会触发缓存功能。

@Cacheable注解还提供了三个属性:value、key和condition。value属性用于指定缓存的名称或命名空间,可以用来区分不同缓存的作用域。key属性用于指定生成缓存键的条件,可以根据方法参数或其他条件生成不同的键,以实现更灵活的缓存策略。condition属性用于指定缓存的条件,只有在符合条件的情况下才会进行缓存。

value属性指定Cache名称

value属性是必须指定的,它表示当前方法的返回值会被缓存在哪个Cache上,也就是对应的Cache的名称。可以指定一个Cache,也可以指定多个Cache。当需要指定多个Cache时,可以使用数组形式。

//Cache是发生在cache1上的
@Cacheable("cache1")
public User find(Integer id) {Return null;
}//Cache是发生在cache1和cache2上的
@Cacheable({"cache1", "cache2"})
public User find(Integer id) {Return null;
}
使用key属性自定义key

key属性用于指定Spring缓存方法返回结果时对应的key。该属性支持使用SpringEL表达式。如果未指定该属性,Spring将使用默认策略生成key。

下面是一个自定义策略的示例,我们可以使用SpringEL表达式来指定key。在EL表达式中,我们可以使用方法参数及其属性。使用方法参数作为key时,可以直接使用“#参数名”或者“#p参数索引”。

案例分析

以下是几个使用参数作为key的示例:

  @Cacheable(value="users", key="#id")public User find(Integer id) {return null;}@Cacheable(value="users", key="#p0")public User find(Integer id) {return null;}@Cacheable(value="users", key="#user.id")public User find(User user) {return null;}@Cacheable(value="users", key="#p0.id")public User find(User user) {return null;}

除了上述使用方法参数作为key的方法外,Spring还提供了一个root对象,可以用来生成key。通过该root对象,我们可以获取以下信息:

  1. 方法名称(#root.methodName):可以获取当前缓存方法的名称。
  2. 目标类名称(#root.targetClass):可以获取当前缓存方法所在的目标类的名称。
  3. 目标对象(#root.target):可以获取当前缓存方法所在的目标对象。
  4. 方法参数(#root.args):可以获取当前缓存方法的参数列表。

使用这些信息作为key的一部分,可以更精确地指定缓存方法的返回结果所对应的key。下面是一个示例:

@Cacheable(value = "myCache", key = "#root.methodName + ':' + #root.targetClass + ':' + #root.args[0]")
public String getSomeData(String key) {// ...
}

在这个示例中,使用了方法名称、目标类名称和第一个参数作为key的一部分,以确保每个不同的参数组合都能生成不同的缓存key。

注意:当我们要使用root对象的属性作为key时,我们也可以省略“#root”

caches

caches:当前被调用的方法使用的Cache,#root.caches[0].name,因为Spring默认使用的就是root对象的属性。下面是一个示例:

@Cacheable(value = {"users", "xxx"}, key = "caches[1].name")
public User find(User user) {return null;
}

在这个示例中,我们使用了root对象的属性caches[1].name作为缓存的key。这意味着根据缓存的设置,当调用这个方法时,Spring将会使用usersxxx这两个缓存的名称,以及caches[1].name作为缓存的key。

condition属性指定发生的条件

有时候,我们可能不希望缓存一个方法的所有返回结果。通过condition属性,我们可以实现这一功能。condition属性的默认值为空,表示缓存所有的调用情况。该属性的值通过SpringEL表达式来指定,当为true时表示进行缓存处理,当为false时表示不进行缓存处理,即每次调用该方法时都会执行一次。下面的示例展示了只有当userid为偶数时才会进行缓存:

@Cacheable(value = "users", key = "#user.id", condition = "#user.id % 2 == 0")
public User find(User user) {// 方法逻辑
}

在这个示例中,我们使用了SpringEL表达式#user.id % 2 == 0作为condition属性的值。这个表达式的含义是只有当userid是偶数时才会进行缓存。如果userid是奇数,则每次调用find()方法时,方法都会执行一次,而不会使用缓存的结果。

@CachePut

@CachePut注解也可以用来声明一个支持缓存功能的方法。与@Cacheable不同之处在于,@CachePut`注解用来标识一个支持缓存功能的方法。它不会在执行之前检查缓存条目,而是每次都执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

使用案例

@CachePut可以用于类和方法级别的标注。使用@CachePut时,我们可以像@Cacheable一样指定属性。

@CachePut(value = "users") // 每次都会执行方法,并将结果存入指定的缓存中
public User find(Integer id) {return null;
}

@CacheEvict

allEntries属性

allEntries是一个布尔类型的属性,表示是否需要清除缓存中的所有元素。默认值为false,表示不需要清除所有元素。当将allEntries设置为true时,Spring Cache将忽略指定的key。有时,我们可以通过清除所有元素来提高效率,而不是逐个清除各个元素。

@CacheEvict(value = "users", allEntries = true)
public void delete(Integer id) {System.out.println("delete user by id: " + id);
}

beforeInvocation属性

清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation属性可以改变触发清除操作的时间,当将该属性值设置为true时,Spring会在调用该方法之前清除缓存中的指定元素。

@CacheEvict(value = "users", beforeInvocation = true)
public void delete(Integer id) {System.out.println("delete user by id: " + id);
}

实际上,在使用Ehcache作为实现时,除了使用@CacheEvict来清除缓存元素之外,我们也可以通过配置Ehcache自身的驱除策略来实现。这可以通过Ehcache的配置文件来指定。

@Caching

@Caching注解可以让我们在一个方法或者类上同时指定多个Spring Cache相关的注解。它拥有三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict。

@Caching定义如下

public @interface Caching {  Cacheable[] cacheable() default {}; //声明多个@Cacheable  CachePut[] put() default {};        //声明多个@CachePut  CacheEvict[] evict() default {};    //声明多个@CacheEvict  
}  

使用案例

@Caching(cacheable = @Cacheable("users"), evict = {@CacheEvict("cache2"),@CacheEvict(value = "cache3", allEntries = true)
})
public User find(Integer id) {return null;
}

自定义缓存注解

上面介绍的@Caching组合,会让方法上的注解显得整个代码比较乱,此时可以使用自定义注解把这些注解组合到一个注解中。

@Caching(  put = {  @CachePut(value = "user", key = "#user.id"),  @CachePut(value = "user", key = "#user.username"),  @CachePut(value = "user", key = "#user.email")  }  
)  
@Target({ElementType.METHOD, ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Inherited  
public @interface WrapperCache {  
}  
@WrapperCache 
public User save(User user)  

Spring允许我们在配置可缓存的方法时使用自定义的注解,前提是自定义的注解上必须使用对应的注解进行标注。例如,我们可以创建一个使用@Cacheable进行标注的自定义注解,如下所示:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Cacheable(value = "users")
public @interface MyCacheable {}

然后,我们可以在需要缓存的方法上使用@MyCacheable进行标注,以实现相同的效果。以下是优化后的示例代码:

@MyCacheable
public User findById(Integer id) {System.out.println("find user by id: " + id);User user = new User();user.setId(id);user.setName("Name" + id);return user;
}

通过这样的设置,方法findById将会被缓存起来,以便在后续调用中直接返回缓存的结果。如果您还有其他问题或需要进一步帮助,请随时告诉我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/11188.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大学的python课程一般叫什么,大学开设python课程吗

大家好,小编为大家解答大学的python课程一般叫什么的问题。很多人还不知道大学python课有没有听的必要,现在让我们一起来看看吧! 1、华中农业大学python期末考试会考原题吗 华中农业大芦如学python期末考试不会考原题。华中农业搜侍大学pyth…

OpenCV图像处理-图像分割-MeanShift

MeanShift 1. 基本概念2.代码示例 1. 基本概念 MeanShift严格说来并不是用来对图像进行分割的,而是在色彩层面的平滑滤波。它会中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉面积较小的的颜色区域,它以图像上任意一点P为圆心&…

配置文件、request对象请求方法、Django连接MySQL、Django中的ORM、ORM增删改查字段、ORM增删改查数据

一、配置文件的介绍 1.注册应用的 INSTALLED_APPS [django.contrib.admin,django.contrib.auth,django.contrib.contenttypes,django.contrib.sessions,django.contrib.messages,django.contrib.staticfiles,app01.apps.App01Config, ]################中间件###############…

UE4/5C++多线程插件制作(十三、优化,bug,尝试打包【尚未完成插件封装,初次测试】)

目录 MTPPlatform.h MTPMarco.h MTPSemaphore.h MTPSemaphore.cpp RTPRunnable.cpp 模板问题 打包问题 MTPPlatform.h 首先我们准备一个跨平台使用的头文件,在ue内部有很多关于跨平台

CSS :nth-child

CSS :nth-child :nth-child 伪类根据元素在同级元素中的位置来匹配元素. CSS :nth-child 语法 值是关键词 odd/evenAnB最新的 [of S] 语法权重 浏览器兼容性 很简单的例子, 来直觉上理解这个伪类的意思 <ul><li class"me">Apple</li><li>B…

websocket服务端,运行后始终无法连接的解决方案

javax.websocket.DeploymentException: The HTTP response from the server [404] did not permit the HTTP 解决办法&#xff1a;少两个文件&#xff1a; WebSocketConfig.java Configuration public class WebSocketConfig {/*** 注入一个ServerEndpointExporter,该Bean…

MySQL 服务器的调优策略

点击上方↑“追梦 Java”关注&#xff0c;一起追梦&#xff01; 在工作中&#xff0c;我们发现慢查询一般有2个途径&#xff0c;一个是被动的&#xff0c;一个是主动的。被动的是当业务人员反馈某个查询界面响应的时间特别长&#xff0c;你才去处理。主动的是通过通过分析慢查询…

在Microsoft Excel中如何快速合并表格

在 Excel 中分析数据时&#xff0c;在一个工作表中收集所有必要信息的频率是多少&#xff1f;几乎从来没有&#xff01;当不同的数据分散在许多工作表和工作簿中时&#xff0c;这是一种非常常见的情况。幸运的是&#xff0c;有几种不同的方法可以将多个表中的数据组合成一个表&…

机器学习深度学习——线性回归的简洁实现

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——线性回归的从零开始实现 &#x1f4da;订阅专栏&#xff1a;机器学习&&深度学习 希望文章对你们…

全球程序员需要知道的50+网址,有多少你第一次听说?

作为程序员&#xff0c;需要知道的50网址&#xff0c;有多少你第一次听说 GitHub (github.com): 最大的代码托管平台&#xff0c;开源项目和代码分享的社区。程序员可以在这里找到各种有趣的项目&#xff0c;参与开源贡献或托管自己的代码。 Stack Overflow (stackoverflow.co…

Python[parquet文件 转 json文件]

将Python中的Parquet文件转换为JSON文件 引言 Parquet是一种高效的列式存储格式&#xff0c;而JSON是一种常见的数据交换格式。我们将使用pandas和pyarrow库来实现这个转换过程&#xff0c;并且提供相关的代码示例。 安装所需库 首先&#xff0c;请确保您已经安装了pandas和…

Rust: Vec类型的into_boxed_slice()方法

比如&#xff0c;我们经常看到Vec类型&#xff0c;但取转其裸指针&#xff0c;经常会看到into_boxed_slice()方法&#xff0c;这是为何&#xff1f; use std::{fmt, slice};#[derive(Clone, Copy)] struct RawBuffer {ptr: *mut u8,len: usize, }impl From<Vec<u8>&g…

垃圾回收之三色标记法(Tri-color Marking)

关于垃圾回收算法&#xff0c;基本就是那么几种&#xff1a;标记-清除、标记-复制、标记-整理。在此基础上可以增加分代&#xff08;新生代/老年代&#xff09;&#xff0c;每代采取不同的回收算法&#xff0c;以提高整体的分配和回收效率。 无论使用哪种算法&#xff0c;标记…

【libevent】http客户端2:使用post 发送本地文件到服务器

HttpClient2POST的例子 看起来只post了一次?#include <stdio.h> #include <assert.h> #include <stdlib.h> #include

深入浅出Pytorch函数——torch.maximum

分类目录&#xff1a;《深入浅出Pytorch函数》总目录 相关文章&#xff1a; 深入浅出Pytorch函数——torch.max 深入浅出Pytorch函数——torch.maximum 计算input和other的元素最大值。 语法 torch.maximum(input, other, *, outNone) -> Tensor参数 input&#xff1a;…

C# OpenCvSharpe 二值化工具 阈值 自适应阈值 局部阈值 InRange

效果 阈值 自适应阈值 局部阈值 InRange 项目 VS2010.net4.0OpenCvSharper3 Demo下载

Educational Codeforces Round 152 (Rated for Div. 2)

B. Monsters 题意&#xff1a;你的攻击力为k&#xff0c;你优先攻击血量最多的怪物&#xff0c;血量相同击杀编号小的&#xff0c;问怪物被击杀的顺序&#xff0c; 思路&#xff1a;我们可以知道最后肯定存在一个状态&#xff0c;所有怪物就差一次攻击就死了&#xff0c;这个…

AWS / VPC 云流量监控

由于安全性、数据现代化、增长、灵活性和成本等原因促使更多企业迁移到云&#xff0c;将数据存储在本地的组织正在使用云来存储其重要数据。亚马逊网络服务&#xff08;AWS&#xff09;仍然是最受追捧和需求的服务之一&#xff0c;而亚马逊虚拟私有云&#xff08;VPC&#xff0…

LED芯片 VAS1260IB05E 带内部开关LED驱动器 汽车硬灯带灯条解决方案

VAS1260IB05E深力科LED芯片是一种连续模式电感降压转换器&#xff0c;设计用于从高于LED电压的电压源高效驱动单个或多个串联连接的LED。该设备在5V至60V之间的输入电源下工作&#xff0c;并提供高达1.2A的外部可调输出电流。包括输出开关和高侧输出电流感测电路&#xff0c;该…

UE4/5C++多线程插件制作(十七、封装协程管理)

目录 MTPThreadInterface.h MTPManageBase.h MTPCoroutinesManage.h MTPManage.cpp MTPManage.h 添加继承: cpp实现: MTPThreadTaskMan