스프링 캐시에서 핵쉼적인 컴포넌트
@EnableCaching 애너테이션을 @Configuration 클래스에 반드시 추가해줘야
캐시 기능이 활성화된다
- Spring Cache 핵심 컴포넌트인 CacheManager, Cache, CacheResolver의 역할과 책임 이해
- 각 구성 요소가 캐시 추상화 계층에서 어떤 역할을 수행하는지 학습
- Cache 객체가 실제 캐시 엔트리를 어떻게 저장, 조회, 삭제하는가?
- CacheResolver가 복잡한 환경에서 동적으로 캐시를 결정하는 방법
Spring Cache 핵심 컴포넌트
Spring Cache는 다음 세 가지 핵심 컴포넌트를 중심으로 동작한다
- CacheManager : 캐시 생성 및 관리
- Cache : 실제 캐시 저장소
- CacheResolver : 캐시 선택 전략 관리
세가지 컴포넌트는 Spring Cache 추상화의 핵심 구조를 구성한다.
각자의 책임을 분리하여 캐시를 유연하고 확장 가능하게끔 만듬
@Cacheable 메서드 - > CacheResolver에서 캐시 전략 선택 - > CacheManager에서 생성 및 관리 - > 이를 Cache에서 가져옴
Hit : Cached Result를 응답
Miss : 메서드 실행 후 응답
CacheManager
1. 역할
CacheManager는 캐시 저장소(Cache)를 생성하고 관리하는 관리자 역할을 함
Spring에서 캐시를 사용할 때, 개발자가 명시적으로 캐시 객체를 만들지 않아도 CacheManager가 알아서 생성하고 관리한다
- 캐시 등록 및 조회 : 지정된 이름의 캐시를 관리함(userCache, productCache 등)
- 캐시 구현체 선택 : Caffeine, EnCache, Redis 등 다양한 구현체를 지원함
- 캐시 일관성 유지 : 여러 캐시 간 데이터 일관성을 관리함
2. CacheManager 구현체의 종류
Spring에서는 캐시 구현체를 지원하기 때문에, 개발 환경에 따라 적절한 CacheManager를 선택할 수 있음
| 구현체 | 설명 | 특징 |
| ConcurrentMapCacheManager | 기본 메모리 기반 캐시 | 설정 없이 바로 사용 가능(테스트환경에 적합) |
| EnCacheCacheManager (인캐시 캐시매니저) |
디스크 기반 캐시 | 대용량 캐시 처리, XML 기반 설정 지원 |
| CaffeineCacheManager | Java 8 기반 고성능 캐시 | 만료정책, 용량제한 등 정교한 설정 가능 |
| RedisCacheManager | 분산 캐시 | 서버간 캐시 공유 및 확장성이 우수함 |
3. 예제 : Caffeine 기반 CacheManager 설정
implementation 참조 : https://yonghwankim-dev.tistory.com/617
build.gradle 설정
// 이 안에 caffeineCacheManager가 들어있음
implementation 'org.springframework.boot:spring-boot-starter-cache'
//caffeine
implementation 'com.github.ben-manes.caffeine:caffeine'
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableCaching
public class CacheConfig {
public CaffeineCacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("userCache", "productCache");
cacheManager.setCaffeine(Caffeine.newBuilder()
.maximumSize(1000) // 최대 캐시 수 제한
.expireAfterWrite(10, TimeUnit.MINUTES)); // TTL 설정, 10분
return cacheManager;
}
}
이렇게 설정하면,
@Cacheable(value = "userCache")와 같은 애너테이션이 지정된 메서드에서 자동으로 Caffeine 캐시를 활용하게 된다고 한다.
Cache
1. 역할
Cache 인터페이스는 캐시 데이터의 CRUD를 담당하는 핵심 컴포넌트임
실제로 캐시 데이터를 저장하거나 읽어오는 작업은 Cache 객체 내부에서 이뤄진다.
| 메서드 | 설명 |
| get(Object key) | 캐시에서 값을 조회함 |
| put(Object key, Object value) | 캐시에 새로운 값을 저장함 |
| evict(Object key) | 특정 키의 캐시를 삭제함 |
| clear() | 모든 캐시 데이터를 삭제함 |
2. 예제 : Cache 직접 사용
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
@Service
public class ProductService {
private final CacheManager cacheManager;
public ProductService(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
public String cacheExample() {
Cache cache = cacheManager.getCache("productCache");
// 캐시에 데이터를 저장함
cache.put("item1", "Laptop");
// 캐시에서 데이터를 조회함
String product = cache.get("item1", String.class);
System.out.println("조회 결과 : " + product);
// 캐시 삭제
cache.evict("item1");
return "조회 결과 : " + product;
}
}
* @Cacheable이 없어도 CacheManager를 통해 직접 캐시를 조회할 수 있다.
3. 캐시 엔트리 관리 다이어그램
CacheResolver
1. 역할
CacheResolver는 복수의 캐시가 존재하는 환경에서, 어떤 캐시를 사용할지 동적으로 결정하는 역할을 함
기본적으로 Spring은 SimpleCacheResolver를 사용하며, CacheManager가 제공하는 캐시를 그대로 사용함
그러나 특정 조건(사용자의 유형, API 경로, 데이터 크기 등..)에 따라 캐시 선택 로직을 커스터마이징해야 하는 경우, 직접 구현할 수 있다고 한다.
2. 예제 : Custom CacheResolver 구현
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.List;
@Component
public class CustomCacheResolver implements CacheResolver {
private final CacheManager cacheManager;
public CustomCacheResolver(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
String methodName = context.getMethod().getName();
// 메서드명에 따라 다른 캐시를 선택한다
if(methodName.startsWith("getUser")) { // 메서드명이 getUser로 시작하면
return List.of(cacheManager.getCache("userCache")); // userCache를 씀
}
return List.of(cacheManager.getCache("defaultCache")); // 아니면 defaultCache를 씀
}
}
* getUser 형태의 메서드(getUser로 시작하는 메서드)는 자동으로 userCache를 사용하게 된다.
3. CacheResolver 동작 다이어그램
@Cacheable 메서드 - > CustomCacheResolver - > 메서드명에 따라 userCache or defaultCache -> CacheManager
팁
* CacheManager는 하나의 빈(bean)으로 등록되어 전역에서 공유된다
* 서비스별로 캐시 정책이 다를 경우, 여러 CacheManager를 만들어 분리 운영할 수 있음
* CacheResolver를 통해 API별 캐시 구분 로직을 추가하면, 대규모 서비스에서 캐시 오염을 방지할 수 있음
* 캐시 이름은 반드시 명확한 도메인 명명 규칙을 따르는게 좋음(userCache, contentCache, articleCache 등)
정리
| 요소 | 역할 | 주요 메서드, 특징 |
| CacheManager | 캐시 생성 및 관리 | getCache(), 다양한 구현체 지원 |
| Cache | 실제 캐시 저장소 | get(), put(), evict(), clear() |
| CacheResolver | 캐시 선택 로직 관리 | resolveCaches() 메서드로 조건별 캐시 선택 |
'Spring Boot > Cache' 카테고리의 다른 글
| Spring Cache 추상화 : Spring Boot 캐시 자동 설정 (0) | 2026.01.09 |
|---|---|
| Spring Cache 추상화 : 캐시 동작 원리 (0) | 2026.01.09 |
| Spring Cache 추상화 : 추상화의 필요성 (0) | 2026.01.05 |
| 캐시 아키텍처와 종류 : 실무 캐시 아키텍처 설계 (0) | 2026.01.04 |
| 캐시 아키텍처와 종류 : 주요 캐시 솔루션 비교 (0) | 2026.01.02 |