spring 提供對 cache 的 API 介面
org.springframework.cache.Cache
org.springframework.cache.CacheManager
如果 application 沒有註冊 CacheManager 或 CacheResolver,spring 會依照以下順序檢測 cache component
Generic -> JCache (JSR-107) (EhCache3, Hazelcast, Infinispan..) -> Hazelcast -> Infinispan -> Couchbase -> Redis -> Caffeine -> Cache2k -> Simple
org.springframework.boot.autoconfigure.AutoConfiguration.imports 有註冊自動設定類別
自動設定類別為 CacheAutoConfiguration,參數綁定類別為 CacheProperties
設定參數 spring.cache.*
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
application.yml
spring:
cache:
type: none
# none 代表禁用 cache
# type: redis
type 可設定為 COUCHBASE/GENERIC/REDIS/HAZELCAST/CACHE2K/CAFFEINE/JCACHE/INFINISPAN/NONE/SIMPLE
預設簡單 cache
如果沒有設定任何 cache 元件,就是使用 Simple,也就是 thread-safe 的 ConcurrentHashMap
pom.xml 加上 web
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
application 要加上 @EnableCaching
@EnableCaching
@SpringBootApplication
public class CacheApplication {
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class, args);
}
}
先建立一個兩數相乘的 cache service
CacheService.java
package com.test.cache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class CacheService {
@Cacheable("calc")
public int multiply(int a, int b) {
int c = a * b;
log.info("{} * {} = {}", a, b, c);
return c;
}
}
@Cacheable
代表該 method 使用 cache,這是用 AOP 的方法做的
一個測試用的 web service
package com.test.cache;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
public class CacheController {
private final CacheService cacheService;
@RequestMapping("/multiply")
public int multiply(@RequestParam("a") int a,
@RequestParam("b") int b) {
return cacheService.multiply(a, b);
}
}
測試網址 http://localhost:8080/multiply?a=2&b=3
重複多測試幾次,console log 上面都還是只有一行 log。代表重複的參數,會直接從 cache 取得結果,不會進入 service
com.test.cache.CacheService : 2 * 3 = 6
Redis Cache
pom.xml 加上 redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.yml
spring:
data:
redis:
host: localhost
port: 6379
database: 0
password: password
redis-cli
# redis-cli -a password
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
1) "calc::SimpleKey [2, 3]"
127.0.0.1:6379> get "calc::SimpleKey [2, 3]"
"\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x00\x06"
可在建立 cache 名稱,time-to-live 代表只存放 10s
spring:
data:
redis:
host: localhost
port: 6379
database: 0
password: password
cache:
type: redis
cache-names: "calc,test"
redis:
time-to-live: "10s"
針對不同 cache 設定不同規則,可透過 RedisCacheManagerBuilderCustomizer
package com.test.cache;
import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import java.time.Duration;
@Configuration
public class CacheConfiguration {
/**
* 比 application.yml 的設定內容優先權高
* @return
*/
@Bean
public RedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer() {
return (builder) -> builder
.withCacheConfiguration("calc", RedisCacheConfiguration
.defaultCacheConfig().entryTtl(Duration.ofSeconds(5)))
.withCacheConfiguration("test", RedisCacheConfiguration
.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)));
}
}
網址 http://localhost:8080/multiply?a=2&b=3
calc, test 兩個 redis cache 都有資料
# redis-cli -a password -n test
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
1) "calc::SimpleKey [2, 3]"
# redis-cli -a password -n calc
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
1) "calc::SimpleKey [2, 3]"