002-spring cache 基于声明式注解的缓存-01-Cacheable annotation
一、简述
1.1、基础概念、缓存注解
| 名称 | 解释 | |
|---|---|---|
| Cache | 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等 | |
| CacheManager | 缓存管理器,管理各种缓存(cache)组件 | |
| @Cacheable | 加缓存 | 主要针对方法配置,能够根据方法的请求参数对其进行缓存,一般放在创建和获取的方法上 |
| @CacheEvict | 删缓存 | 清空缓存,用于删除的方法上 |
| @CachePut | 重新加缓存 | 保证方法被调用,又希望结果被缓存。 与@Cacheable区别在于是否每次都调用方法,常用于更新 |
| @EnableCaching | 开启基于注解的缓存 | |
| keyGenerator | 缓存数据时key生成策略 | |
| serialize | 缓存数据时value序列化策略 | |
| @CacheConfig | 统一配置本类的缓存注解的属性,与其它缓存配合使用 |
1.2、三个操作缓存注解@Cacheable/@CachePut/@CacheEvict 主要的参数
| 名称 | 解释 |
|---|---|
| value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:@Cacheable(value=”mycache”) 或者@Cacheable(value={”cache1”,”cache2”}) |
| key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如:@Cacheable(value=”testcache”,key=”#id”) |
| condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存/清除缓存 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
| unless | 否定缓存。当条件结果为TRUE时,就不会缓存。 @Cacheable(value=”testcache”,unless=”#userName.length()>2”) |
| allEntries (@CacheEvict ) |
是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 例如:@CachEvict(value=”testcache”,allEntries=true) |
| beforeInvocation (@CacheEvict) |
是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 例如:@CachEvict(value=”testcache”,beforeInvocation=true) |
1.3、上述注解会有条件-SpEL上下文数据
Spring Cache提供了一些供我们使用的SpEL上下文数据,下表直接摘自Spring官方文档:
| 名称 | 位置 | 描述 | 示例 |
|---|---|---|---|
| methodName | root对象 | 当前被调用的方法名 | #root.methodname |
| method | root对象 | 当前被调用的方法 | #root.method.name |
| target | root对象 | 当前被调用的目标对象实例 | #root.target |
| targetClass | root对象 | 当前被调用的目标对象的类 | #root.targetClass |
| args | root对象 | 当前被调用的方法的参数列表 | #root.args[0] |
| caches | root对象 | 当前方法调用使用的缓存列表 | #root.caches[0].name |
| Argument Name | 执行上下文 | 当前被调用的方法的参数,如findArtisan(Artisan artisan),可以通过#artsian.id获得参数 | #artsian.id |
| result | 执行上下文 | 方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false) | #result |
注意:
1.当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。 如
@Cacheable(key = "targetClass + methodName +#p0")
2.使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。 如:
@Cacheable(value="users", key="#id")
@Cacheable(value="users", key="#p0")
SpEL提供了多种运算符
| 类型 | 运算符 |
|---|---|
| 关系 | <,>,<=,>=,==,!=,lt,gt,le,ge,eq,ne |
| 算术 | +,- ,* ,/,%,^ |
| 逻辑 | &&,||,!,and,or,not,between,instanceof |
| 条件 | ?: (ternary),?: (elvis) |
| 正则表达式 | matches |
| 其他类型 | ?.,?[…],![…],^[…],$[…] |
二、缓存Key 与 缓存解析器
2.1、缓存Key说明
2.1.1、默认Key生成
由于缓存本质上是键值存储,因此每次缓存方法的调用都需要转换为适合缓存访问的key。抽象缓存使用一个简单的基于以下算法KeyGenerator:
如果没有给出参数,则返回SimpleKey.EMPTY。
如果只给出一个参数,则返回该实例。
如果给出了多于一个参数,返回一个包含所有参数的SimpleKey。
这种方法适用于大多数使用情况;只要参数具有自然键并实现有效的hashCode()和equals()方法。如果情况并非如此,那么战略需要改变。
为了提供不同的默认key生成器,需要实现org.springframework.cache.interceptor.KeyGenerator接口。
注意:默认的key生成策略随着Spring 4.0的发布而改变。 Spring的早期版本使用了一种key生成策略,对于多个关键参数,只考虑参数的hashCode()而不考虑equals();这可能会导致意外的键碰撞(请参阅SPR-10237的背景)。新的'SimpleKeyGenerator'使用复合键来实现这种场景。
如果您想继续使用以前的key策略,则可以配置弃用的org.springframework.cache.interceptor.DefaultKeyGenerator类或创建基于散列的自定义“KeyGenerator”实现。
2.1.2、自定义key生成策略
由于缓存是通用的,因此目标方法很可能具有不能简单映射到缓存结构顶部的各种签名。当目标方法有多个参数,其中只有一些适用于缓存(而其余的仅由方法逻辑使用)时,这会变得很明显。例如:
@Cacheable("books")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
对于这种情况,@Cacheable注解允许用户指定如何通过其关键属性生成key。开发人员可以使用SpEL来选择感兴趣的参数(或它们的嵌套属性),执行操作甚至调用任意方法,而无需编写任何代码或实现任何接口。这是对默认生成器的推荐方法,因为方法与代码库增长的方式在签名方面往往有很大不同;而默认策略可能适用于某些方法,但对于所有方法都很少。
@Cacheable(cacheNames="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) @Cacheable(cacheNames="books", key="#isbn.rawNumber")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) @Cacheable(cacheNames="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
上面的代码片段显示了选择某个参数,它的一个属性,甚至是一个任意的(静态)方法是多么简单。
如果负责生成key的算法过于具体或者需要共享,您可以在操作中定义一个自定义keyGenerator。为此,请指定要使用的KeyGenerator bean实现的名称:
@Cacheable(cacheNames="books", keyGenerator="myKeyGenerator")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
注意:key和keyGenerator参数是互斥的,指定两者的操作将导致异常。
2.2、缓存解析器
2.2.1、默认缓存解析器
缓存抽象使用一个简单的CacheResolver,它使用配置的CacheManager检索在操作级别定义的缓存。
要提供不同的默认缓存解析器,需要实现org.springframework.cache.interceptor.CacheResolver接口。
2.2.2、自定义缓存解析器
默认的缓存解析非常适合使用单个CacheManager并且不需要复杂的缓存解析要求的应用程序。对于使用多个缓存管理器的应用程序,可以将cacheManager设置为使用每个操作:
@Cacheable(cacheNames="books", cacheManager="anotherCacheManager")
public Book findBook(ISBN isbn) {...}
也可以完全以与key生成类似的方式替换CacheResolver。该解决方案针对每个缓存操作进行请求,给予实现基于运行时参数实际解析要使用的缓存的机会:
@Cacheable(cacheResolver="runtimeCacheResolver")
public Book findBook(ISBN isbn) {...}
注意:自Spring 4.1以来,缓存注释的值属性不再是强制性的,因为无论注释的内容如何,CacheResolver都可以提供此特定信息。
与key和keyGenerator类似,cacheManager和cacheResolver参数是互斥的,指定两者的操作将导致出现异常,因为CacheResolver实现将忽略自定义CacheManager。这可能不是你所期望的。
002-spring cache 基于声明式注解的缓存-01-Cacheable annotation的更多相关文章
- 002-spring cache 基于声明式注解的缓存-02-CachePut、CacheEvict、Caching、CacheConfig、EnableCaching、自定义
1.2.CachePut annotation 在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素 ...
- Spring Cloud Feign 声明式服务调用
目录 一.Feign是什么? 二.Feign的快速搭建 三.Feign的几种姿态 参数绑定 继承特性 四.其他配置 Ribbon 配置 Hystrix 配置 一.Feign是什么? 通过对前面Sp ...
- SSM实战——秒杀系统之Service层接口设计与实现、Spring托管、声明式事务
一:Service层接口设计 准备工作:新建三个包:service包.exception包.dto包,分别用来存放业务接口.自定义异常类.dto类. 1:定义接口 package org.myseck ...
- Spring Cloud07: Feign 声明式接口调用
一.什么是Feign Feign也是去实现负载均衡,但是它的使用要比Ribbon更加简化,它实际上是基于Ribbon进行了封装,让我们可以通过调用接口的方式实现负载均衡.Feign和Ribbon都是由 ...
- Spring AOP实现声明式事务代码分析
众所周知,Spring的声明式事务是利用AOP手段实现的,所谓"深入一点,你会更快乐",本文试图给出相关代码分析. AOP联盟为增强定义了org.aopalliance.aop.A ...
- Spring自学教程-声明式事务处理(六)
Spring事务处理分两种: 一.编程式事务:在程序中控制事务开始,执行和提交: 1.1 使用TransactionTemplate, 使用回调函数执行事务,不需要显示开始事务,不需要显示提交事务,但 ...
- 9.Spring整合Hibernate_2_声明式的事务管理(Xml的方式)
使用xml的方式进行声明式的事务管理 推荐使用xml的方式,因为可以同时为多个方法进行声明 <!-- 开启Spring中的事务管理(声明式的事务管理) xml--> <!-- 不管是 ...
- 8.Spring整合Hibernate_2_声明式的事务管理(Annotation的方式)
声明式的事务管理(AOP的主要用途之一) (Annotation的方式) 1.加入annotation.xsd 2.加入txManager bean 3.<tx:annotation-drive ...
- Spring Cloud Feign声明式服务调用(转载)+遇到的问题
转载:原文 总结: 1.pom添加依赖 2.application中填写正确的eureka配置 3.启动项中增加注解 @EnableFeignClients 4.填写正确的调用接口 通过原文使用Fei ...
随机推荐
- <img/>标签onerror事件在IE下的bug和解决方法
IE下打开网页时,会弹出“Stack overflow at line: 0”的弹框.经分析,这个bug是由于img标签的onerror事件引起的.程序中用到的代码片段如下:正常情况下显示src所指路 ...
- SVN中Revert changes from this revision 跟Revert to this revision
譬如有个文件,有十个版本,假定版本号是1,2,3,4,5,6,7,8,9,10. Revert to this revision: 如果是在版本6这里点击“Revert to this revisio ...
- 创建ros的程序包--3
创建ros的程序包(原创博文,转载请标明出处--周学伟http://www.cnblogs.com/zxouxuewei/) 1.一个catkin程序包由什么组成? 一个程序包要想称为catkin程序 ...
- 查看磁盘读写:iostat
iostat命令用来查看磁盘IO的读写情况,用法如下: [root@localhost ~]$ yum install -y sysstat # 安装iostat命令 [root@localhost ...
- 使用fetch出现unexpected end of input 解决方法
传统的ajax(即xmlhttprequest)由于使用叫复杂,于是js新推出了fetch来获取后台数据,无需引进jq的$.ajax,也可以使用promise的链式用法去处理回调地狱,着实很方便,在谷 ...
- Java语言基本数据类型
■Java是一种强类型语言,每个变量都必须声明其类型.■Java的数据类型分为两大类:基本类型和引用类型(引用数据类型的大小统一为4个字节,记录的是其引用对象的地址).■Java中定义了3类8种基本数 ...
- 正则表达式—RegEx(RegularExpressio)(三)
今日随笔,继续写一点关于正则表达式的 知识.前两天介绍了正则表达式验证匹配,提取等一些基本的知识,今天继续分享下它的另一个强大的应用:替换(replace). 开始之前,还是要补一下昨天的内容. 在我 ...
- 使用commons-email解析 eml文件
在对eml文件进行索引的时候需要先对其进行解析,提取出其中的收件人.发件人.文件内容和附件等信息 下边是解析eml文件的一个demo(在运行之前需要先导入mail.jar 和commons-email ...
- Windows Phone 在读取网络图片之前先显示默认图片
1.新建一个控件WindowsPhoneControl1 WindowsPhoneControl1.xaml <UserControl x:Class="DefaultImage.Wi ...
- 如何设置Eclipse工作区默认编辑宽度
1)打开Window => Preferences窗口 2)打开Formatter属性页从Java => CodeStyle => Formatter 3) 单击New创建一个自己 ...