1. 使用入门
1. 添加依赖
在spring boot中使用spring caching需要先引入依赖:
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-cache</artifactid>
<version>3.1.5</version>
</dependency>spring caching是构建在spring context的基础上的,如果原先没有它的引用的话,需要添加对应的依赖
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-context</artifactid>
<version>6.0.13</version>
</dependency>spring context support里提供了ehcache和caffeine的cachemanager抽象,如果你打算用这两个缓存实现的话,还有依赖
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-context-support</artifactid>
<version>6.0.13</version>
</dependency>2. 启用缓存
在已经添加了spring-boot-starter-cache的前提下,只需要使用@enablecaching注解,spring会默认创建一个concurrentmapcachemanager负责缓存,不过它并不支持缓存过期。 除此以外,我们也可以手动创建cachemanager
@configuration
@enablecaching
public class cachingconfig {
@bean
public cachemanager cachemanager() {
return new concurrentmapcachemanager("users");
}
}3. 集成ehcache
添加ehcache的依赖
<!-- ehcache -->
<dependency>
<groupid>org.ehcache</groupid>
<artifactid>ehcache</artifactid>
</dependency>
<!-- spring integration for ehcache -->
<dependency>
<groupid>javax.cache</groupid>
<artifactid>cache-api</artifactid>
</dependency>
<dependency>
<groupid>org.ehcache</groupid>
<artifactid>ehcache-jsr107</artifactid>
</dependency>在src/main/resources创建配置文件ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:nonamespaceschemalocation="http://ehcache.org/ehcache.xsd">
<cache name="card:id"
maxentrieslocalheap="1000"
eternal="false"
timetoidleseconds="10"
timetoliveseconds="30"
memorystoreevictionpolicy="lru"/>
</ehcache>4. @cachable
这是最常用的注解,如果缓存中存在,返回缓存中的数据,否则调用方法计算,并将结果写入缓存
@cacheable("card:id")
public string getcardbyid(long id) {...}添加了这个注解,相当于执行伪代码
string data = cachemanager.get(cachekey)
if(data == null) {
data = getcardbyid(id)
cachemanager.put(cachekey, data)
}
return cached;@cachable还有一个sync属性,设置为true时会对缓存加载用cachekey做同步,如果加了注解@cacheable("card:id", sync=true)的话,伪代码如下
string data = cachemanager.get(cachekey)
if(data == null) {
synchronized(cachekey) {
data = cachemanager.get(cachekey);
if(data == null) {
data = getcardbyid(id)
cachemanager.put(cachekey, data)
}
}
}
return cached;关于cachekey的生成逻辑,见后续章节。
5. @cacheevict
用于从缓存中删除数据,假设我们有一个更新card的接口,调用会清除card:id下的所有缓存。
@cacheevict(value="card:id", allentries=true)
public string updatecardbyid(long cardid, customer customer) {...}我们可以可以清除指定key的数据,key用spel来计算
@cacheevict(value="card:id",, key = "'card_' + #cardid")
public string updatecardbyid(long cardid, customer customer) {...}6. @cacheput
用于更新缓存数据,想@cacheable的区别是,它不会检查缓存中是否有数据,始终都调用方法获取数据,并更新缓存。
@cacheput("card:id")
public string getcardbyid(long id) {...}7. @caching
用在一个方法上有多个缓存操作的时候,比如
@caching(evict = {
@cacheevict("addresses"),
@cacheevict(value="directory", key="#customer.name") })
public string getaddress(customer customer) {...}8. @cacheconfig
用于设置service级别的缓存配置,比如customerdataservice的方法都操作addresses这个缓存,可以这么配置
@cacheconfig(cachenames={"addresses"})
public class customerdataservice {
@cacheable
public string getaddress(customer customer) {...}
}9. condition/unless
基于条件的缓存,condition基于入参判断,unless基于返回值判断
@cacheput(value="addresses", condition="#customer.name=='tom'")
public string getaddress(customer customer) {...}
@cacheput(value="addresses", unless="#result.length()<64")
public string getaddress(customer customer) {...}2. 定制能力
1. key生成
spring提供了keygenerator来实现key的生成,spring 4.0之后默认采用simplekeygenerator来生成key,逻辑如下:
- 方法没有参数的话,默认返回simplekey.empty
- 方法就一个参数,返回这个参数值
- 方法有多个参数,将参数封装为
simplekeysimplekey会计算hashcode来作为缓存读写的key,如果你不想要这个默认行为,可以通过spel自定义key,比如
@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)
除此以外,还可以自定义keygenerator,将自定义的keygenerator定义为bean后,在注解中引用
@cacheable(cachenames="books", keygenerator="mykeygenerator") public book findbook(isbn isbn, boolean checkwarehouse, boolean includeused)
spel中可以使用的变量如下
| name | description | example |
|---|---|---|
methodname | 方法名 | #root.methodname |
method | 方法 | #root.method.name |
target | 当前方法所属的实例 | #root.target |
targetclass | 当前方法所在的类 | #root.targetclass |
args | 方法的入参 | #root.args[0] |
caches | 对应的缓存 | #root.caches[0].name |
| 参数名 | 方法入参名,java编译时带(-parameters)。否则使用#a<#idx> ,其中#idx是参数的位置(从0开始) | #iban or #a0 |
result | 方法返回值,只在unless、@cacheput的key、@cacheevict设置beforeinvocation=false时可用。如果返回值用来包装类(如optional),#result引用的是内部对象 | #result |
2. 自定义cachemanager
spring提供了ehcache和caffeine的默认实现,如果使用没有默认实现的cache,可以通过自定义cachemanager来实现
@bean
cachemanager cachemanager() {
caffeinecachemanager cachemanager = new caffeinecachemanager();
cachemanager.setcachespecification(...);
cachemanager.setasynccachemode(true);
return cachemanager;
}3. 实现原理
1. cache抽象
spring定义了一个cache接口,用来实现缓存的写入、读取和清理,通过cachemanager、cacheresolver创建cache对象,集成spring boot starter cache的时候其实就是创建cachemanager。通过将keygenerator生成缓存key,传递给cache,来设置或读取缓存。

2. 注解实现
通过aop代理了标注@cacheable、@cacheevict、@cacheput等注解的方法,程序的入口在proxycachingconfiguration中,他会创建advisor和interceptor,实现对bean对象的aop。beanfactorycacheopertionsourceadvisor内部使用cacheoperationsource来过滤切点类,如果我们是基于annotation来使用缓存的话,实现类是annotationcacheoperationsource,它负责失败方法上的@cacheable等注解。实际的缓存逻辑由cacheinterceptor实现,核心代码在cacheaspectsupport类内,尤其是execute方法。

cacheaspectsupport的execute方法的核心逻辑就是生成key、读取缓存、实际调用方法、写入缓存。

a. 参考文档 https://docs.spring.io/spring-framework/reference/integration/cache/annotations.html
到此这篇关于spring cache的使用的文章就介绍到这了,更多相关spring cache使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论