Spring Boot 2.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”,则把返回结果缓存起来。如果不是,就不进行缓存。

模拟网络延迟的代码

import lombok.extern.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结束
- 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(否决)、不缓存

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值