SpringBoot2.0+使⽤Redis做缓存,@Cacheable注解的unless
参数详解
需求概述
在Spring boot 中,⽤Redis作为缓存,在指定⽅法上使⽤@Cacheable注解,并且在缓存时,排除特定返回值
结论
@Cacheable中,unless参数的作⽤是:函数返回值符合表达式条件的,veto(否决)、不缓存
换句话说,函数返回值符合条件的排除掉、只缓存其余不符合条件的
⾼效⼀些,我先把结论写在前⾯。感兴趣的朋友可以继续阅读具体的论证过程。
部分代码实现
具体⽅法
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
/**
* created at 2019-02-01 18:05
* @author lerry
*/
@Component
public class ForCacheService {
@Cacheable(value = "fruit", key = "#param", unless = "!#result")
public boolean isApple(String param) {
LatencyService.sleepAWhile(3);
if (param.equals("apple")) {
return true;
}
else {
return false;
}
}
}
我们定义了⼀个isApple⽅法。想要实现的功能为:如果⼊参是“apple”,则把返回结果缓存起来。如果不是,就不进⾏缓存。
模拟⽹络延迟的代码
slf4j.Slf4j;
/**
* created at 2019-02-01 14:52
* @author lerry
*/
@Slf4j
public class LatencyService {
/**
* 模拟延迟
* @param seconds
*/
public static void sleepAWhile(int seconds) {
try {
log.info("模拟延迟{}s开始", seconds);
Thread.sleep(seconds * 1000L);
log.info("模拟延迟{}s结束", seconds);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试代码
@Autowired
private ForCacheService forCacheService;
@Test
public void testBooelanReturn() {
log.info("apple is apple ? {}", forCacheService.isApple("apple"));
log.info("apple is apple ? {}", forCacheService.isApple("apple"));
log.info("apple is apple ? {}", forCacheService.isApple("apple"));
log.info("orange is apple ? {}", forCacheService.isApple("orange"));
log.info("orange is apple ? {}", forCacheService.isApple("orange"));
log.info("orange is apple ? {}", forCacheService.isApple("orange"));
}
测试返回结果
-
模拟延迟3s开始
- 模拟延迟3s结束
- apple is apple ? true
- apple is apple ? true
- apple is apple ? true
- 模拟延迟3s开始
- 模拟延迟3s结束
- orange is apple ? false
- 模拟延迟3s开始
- 模拟延迟3s结束
- orange is apple ? false
-
模拟延迟3s开始
- 模拟延迟3s结束
- orange is apple ? false
可以看到,当参数是apple时,第⼀次访问,程序执⾏了3秒延迟的代码。但是第⼆次、第三次执⾏时,直接从缓存获取了结果。 当参数是orange时,没有进⾏缓存。第⼆次、第三次访问,都进⾏了3秒延迟
unless的详细解释
unless = "!#result"
其中#result,代指函数的返回值。⾮(!)(返回值),都进⾏缓存。 就是说,当返回值不是false时,才进⾏缓存。这样解释,可能⽐较绕。接下来,我换个写法,再解释⼀遍。
我们实现⼀个String类型返回值的函数。这个函数很简单,返回值就是⼊参:
@Cacheable(value = "str", key = "#param", unless = "#result eq 'abc'")
public String stringDemo(String param) {
LatencyService.sleepAWhile(3);
return param;
}
测试代码
@Test
public void testStrReturn() {
log.info("123:{}", forCacheService.stringDemo("123"));
log.info("123:{}", forCacheService.stringDemo("123"));
log.info("123:{}", forCacheService.stringDemo("123"));
log.info("456:{}", forCacheService.stringDemo("456"));
log.info("456:{}", forCacheService.stringDemo("456"));
log.info("456:{}", forCacheService.stringDemo("456"));
log.info("abc:{}", forCacheService.stringDemo("abc"));
log.info("abc:{}", forCacheService.stringDemo("abc"));
log.info("abc:{}", forCacheService.stringDemo("abc"));
}
测试结果
- 模拟延时3s开始
- 模拟延时3s结束
- 123:123
- 123:123
- 123:123
-
模拟延时3s开始
- 模拟延时3s结束
- 456:456
- 456:456
- 456:456
- 模拟延时3s开始
- 模拟延时3s结束
cacheable- abc:abc
- 模拟延时3s开始
- 模拟延时3s结束
- abc:abc
-
模拟延时3s开始
- 模拟延时3s结束
- abc:abc
可以很明显的看到,除了abc没有被缓存,其余不等于abc的字符串,都被缓存了。
unless = "#result eq 'abc'的含义为:
函数返回值符合条件的,不缓存。
或者说:
除了符合el表达式条件的,其余的都进⾏缓存。
API⽂档注释
Spring Expression Language (SpEL) expression used to veto method caching.
Unlike condition, this expression is evaluated after the method has been called and can therefore refer to the result.
Default is “”, meaning that caching is never vetoed.
翻译:
⽤于否决⽅法缓存的 Spring表达式语⾔(SpEL) 表达式。
与condition不同,这个表达式是在调⽤⽅法之后计算的,因此可以引⽤结果(⽅法返回结果)。
默认值是“”,这意味着缓存从未被否决。
所以,可以这样理解:
函数返回值符合表达式条件的,veto(否决)、不缓存
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论