Spring Boot 2.0+使用Redis做緩存,@Cacheable註解的unless參數詳解

需求概述

在Spring boot 中,用Redis作爲緩存,在指定方法上使用@Cacheable註解,並且在緩存時,排除特定返回值

結論

@Cacheable中,unless參數的作用是:函數返回值符合EL表達式條件的,不緩存。
換句話說,函數返回值符合條件的排除掉、只緩存其餘不符合條件的
高效一些,我先把結論寫在前面。感興趣的朋友可以繼續閱讀具體的論證過程。

部分代碼實現

具體方法

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秒延遲。
redis

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的字符串,都被緩存了。
str緩存
unless = "#result eq 'abc'的含義爲:
函數返回值符合條件的,不緩存。
或者說:
除了符合el表達式條件的,其餘的都進行緩存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章