SpringBoot Cache
uwupu 啦啦啦啦啦

Spring Cache

https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#cache-annotations

Spring提供了能够缓存方法调用结果的注解:@Cacheable,@CacheEvict,@CachePut,@Caching,@CacheConfig。

该注解可以用在任何方法中。

@Cacheable

使用

@Cacheable可以注解在需要缓存的方法上。

通过@Cacheable可以设定:

  • 缓存使用的CacheName
  • 缓存存放的key;
  • 缓存的条件;

设定注解的value后,当方法被调用,Spring会把返回值存放在名为CacheName的缓存中,将参数Hash后的值作为key,返回值作为value。

当下次以相同参数调用方法时,Spring将从缓存中取出上次的结果,然后将结果返回,本次不调用该方法。

一个示例

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@EnableCaching //需要在启动类或@Configuration类上添加@EnableCaching注解表示启用缓存
public class SpringBootGetIpStudyApplication {

public static void main(String[] args) {
SpringApplication.run(SpringBootGetIpStudyApplication.class, args);
}

}
1
2
3
4
5
6
7
8
@RestController
public class SpringBootCacheStudyController {
@GetMapping("/get")
@Cacheable("cache_study")
public String get(int s){
return UUID.randomUUID().toString().substring(0,10);
}
}

在一次运行过程中,多次请求https://127.0.0.1/get?s=1,获取的结果都是一致的。

缓存中的key

缓存的实现本质是键值存储。

若方法没有参数,将以SimpleKey.EMPTY作为key将结果存放;

若方法有一个参数,则直接以这个参数作为key;

若方法有多个参数,则返回一个包含所有参数的SimpleKey。(hashCode()的结果)

若方法有多个参数,可以指定一个SpEL表达式作为SimpleKey进行存储。

1
2
3
4
5
@GetMapping("/get5")
@Cacheable(cacheNames = "cache_study",key = "#a")
public String get5(int a,int b,int c){
return UUID.randomUUID().toString().substring(0,10);
}

无论b和c为多少,只有a改变时,缓存才会发生改变。

同步缓存

在多线程环境中,可能会有多个线程同时调用同一个方法;

默认缓存不锁定任何东西,可能会导致多次调用,然后达到同样的缓存结果。

对于这种情况,可以使用sync属性;

添加该属性后,在多个线程调用方法时,只有一个线程用于计算,其他线程被阻塞直到缓存被更新。

1
2
@Cacheable(cacheNames="foos", sync=true) 
public Foo executeExpensiveOperation(String id) {...}

条件缓存

可以设定达到指定的条件再进行缓存,使用参数condition。使用SpEL表达式作为值。

根据参数进行条件缓存

condition
1
2
3
4
5
@GetMapping("/get2")
@Cacheable(cacheNames = "cache_study",condition = "#s>10")
public String get2(int s){
return UUID.randomUUID().toString().substring(0,10);
}

当s的值大于10,则进行缓存。

1
2
3
4
5
@GetMapping("/get3")
@Cacheable(cacheNames = "cache_study",condition = "#s.length()>3")
public String get3(String s){
return UUID.randomUUID().toString().substring(0,10);
}

当字符串s长度大于3时进行缓存。

unless

unless发生在方法调用结束之后,也用来判断是否需要缓存,这个属性不会控制方法是否被调用

unless的属性值表现方式与condition相反,译为“如果不”,则进行缓存。

可以使用#result来代表返回的对象,填充属性值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@GetMapping("/get4")
@Cacheable(cacheNames = "cache_study",unless = "#result.id>10")
public Water get4(int id){
return new Water(id);
}
class Water{
int id;
String uuid;
public Water(int id) {
this.id = id;
this.uuid = UUID.randomUUID().toString().substring(0,10);
}
//getter,setter,toStirng方法省略。
}

当方法调用返回的对象的id小于等于10,则返回缓存的结果,本地调用返回的结果丢弃。

反之,将本次调用的结果存到缓存中

SpEL表达式可以用的元参数
NameLocationDescriptionExample
methodNameRoot object被调用的方法名#root.methodName
methodRoot object被调用的方法#root.method.name
targetRoot object被调用的目标对象#root.target
targetClassRoot object目标对象的class#root.targetClass
argsRoot object被调用的参数列表#root.args[0]
cachesRoot object当前方法调用使用的缓存列表。(如@Cacheable({“cache1”,“cache2”}))#root.caches[0].name
Argument nameEvaluation context方法参数的名字,使用#参数名,也可以使用#p0#a0,0代表参数的索引#apple #p0 #a1
resultEvaluation context方法执行后的返回值#result

@CachePut

使用@CachePut注解的方法,方法总会被调用执行,并且会将调用结果放到缓存中。

@CacheEvict

使用@CacheEvict注解可以对缓存进行清理。

可以指定一个或多个缓存清理,允许指定key或条件进行缓存,另可以带一个参数allEntries表示是否需要清理所有的缓存。

1
2
@CacheEvict(cacheNames="books", allEntries=true) 
public void loadBooks(InputStream batch)

清理cacheNames为books的缓存。

@Caching

@Caching注解可以让多个相同的注解进行嵌套。

1
2
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })
public Book importBooks(String deposit, Date date)

@CacheConfig

@CacheConfig注解用在类上,可以为整个类共享一个CacheName。

在方法上的@Cachable注解不需要添加CacheName属性,就可以实现缓存;

若类里面有一个方法的@Cachable注解有CacheName属性,则该方法使用自己的CacheName,不共享类的CacheName。

若方法没有被@Cachable注解,则不会进行缓存。

@EnableCaching

要使以上的注解生效,需要在启动类或配置类上添加@EnableCaching注解。

 评论
评论插件加载失败
正在加载评论插件
由 Hexo 驱动 & 主题 Keep
总字数 163.9k 访客数 访问量