(Spring Boot 3) Mono 캐싱하기 (with caffeine)
Spring 6.1.0 부터, 반환타입 Mono
에도 @Cacheable
사용이 가능하다.
코루틴 suspend func에 사용하는 것도 6.1.0 부터 가능하다.
설정 예시
CacheGroup
1
2
3
4
5
6
7
8
9
10
11
enum class CacheGroup(
val cacheName: String,
val ttl: Duration,
) {
VAS(Names.VAS, Duration.ofMinutes(10)),
;
object Names {
const val VAS = "VAS"
}
}
CacheConfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@EnableCaching
@Configuration
class CacheConfig {
@Bean
fun caffeineCacheManager(): CaffeineCacheManager =
CaffeineCacheManager().apply {
getCaffeineCacheList().forEach {
registerCustomCache(it.name, it.asyncCache)
}
setAsyncCacheMode(true) // AsyncCacheMode 설정해줘야 Mono에 동작.
}
/**
* Caffeine 객체를 직접 생성 할 때 원하는 대로 커스터마이징이 가능하다.
* - eviction listener 등록
* - expire 시 자동 refresh 설정 등
*/
private fun getCaffeineCacheList(): List<CaffeineCache> =
CacheGroup.entries.map { cacheGroup ->
CaffeineCache(
cacheGroup.cacheName,
Caffeine.newBuilder().recordStats()
.expireAfterWrite(cacheGroup.ttl)
.buildAsync<Any, Any>(),
// Async로 생성해줘야 Mono에 동작. 일반 동기식 함수에 붙여도 동작한다.
true,
)
}
}
SimpleCacheManager
를 사용하는 예제가 많이 보이는데, 카페인을 쓰는데 카페인 캐시 매니저를 쓰는게 더 알맞지 않나 싶다.
게다가 async 설정은 CaffeineCacheManager
를 써야만 가능하다.
사용처
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
class MyService {
@Cacheable(CacheGroup.Names.VAS)
fun aaa(): Mono<String> {
logger.info("### async A 호출 테스트")
return Mono.just("aaa") // .cache()는 호출하지 않는다.
}
@Cacheable(CacheGroup.Names.VAS)
fun bbb(): String { // buildAsync 했지만 동기식 함수에 붙여도 동작한다.
logger.info("### sync B 호출 테스트")
return "bbb"
}
}
주의 사항
cacheName + 메서드 파라미터
가 같으면 캐시 결과를 공유한다.- 이런 경우 리턴 타입이 다른 두 메서드에 적용하면, 이후에 호출되는 메서드는 캐시 결과를 가져오다가 리턴 타입이 안맞아
ClassCastException
발생한다. - 메서드 파라미터 다른 것으로 구분하지 말고, 아예
cacheName
을 다르게 주는 것이 안전하다.
- 이런 경우 리턴 타입이 다른 두 메서드에 적용하면, 이후에 호출되는 메서드는 캐시 결과를 가져오다가 리턴 타입이 안맞아
- 위 예제에서
aaa() / bbb()
는cacheName + 메서드 파라미터
가 같기 때문에 캐시를 공유한다.aaa()
를 먼저 호출한 경우,bbb() => "aaa"
를 반환bbb()
를 먼저 호출한 경우,aaa() => "bbb"
를 반환- 하나는 반환타입이
Mono<String>
이고 하나는String
임에도 결과를 공유한다. (캐시 결과를 내놓을 때 callee 메서드의 반환 타입은 전혀 신경쓰지 않기 때문)
This post is licensed under CC BY 4.0 by the author.