CacheManager는 캐시를 관리해주는 매니저이다.
일반적으로 스프링에서 캐시를 관리해주는 매니저는 두 가지가 있다.
SimpleCacheManager, ConcurrentMapCacheManager
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("user", "product");
}
}
@EnableCaching 붙이면 스프링은 자동으로 CacheManager 빈을 찾아서 사용하게 된다.
@Bean으로 직접 지정하면 그 쪽이 우선시되게 된다.
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
이러한 의존성을 추가해줌으로서 스프링 내부에서 CacheManager을 사용할 수 있게 된다.
| 컴포넌트 | 설명 |
|---|---|
RedisTemplate | Redis에 직접 명령어 날릴 수 있는 템플릿 |
RedisCacheManager | @Cacheable과 함께 사용하는 캐시 매니저 |
RedisConnectionFactory | 실제 Redis 연결을 만들어주는 팩토리 |
RedisSerializer | JSON, JDK 직렬화 등 Value 변환기 |
Lettuce | 기본 Redis 클라이언트 (비동기, 넌블로킹) |
이것은 우리가 직접 구현해야할 것이다.
@Cacheable / @CachePut / @CacheEvict
↓
CacheManager (인터페이스)
↓
├─ SimpleCacheManager → JVM 캐시
├─ ConcurrentMapCacheManager → 쓰레드 세이프 JVM 캐시
└─ RedisCacheManager ✅ Redis 연동용 캐시 매니저
@Cacheable(value = "user", key = "#id")
public User getUserById(Long id) {
return userRepository.findById(id).orElseThrow();
}
이렇게 찾은 db의 조회 결과를 캐시에 저장하게 되는데 이 코드 실행시 Spring 내부 동작은 다음과 같다.
→ “user라는 이름의 캐시 공간(Cache)을 써야겠군!”
cacheManager.getCache("user")
→ @Configuration에서 너가 @Bean으로 등록한 CacheManager
@Bean
public CacheManager cacheManager() {
return new RedisCacheManager(...); // 또는 ConcurrentMapCacheManager
}
RedisCacheManager라면 → Redis에 "user::id" 형태로 저장
ConcurrentMapCacheManager라면 → JVM 메모리에 "user::id"로 저장
만약에 너가 RedisCacheManager랑 ConcurrentMapCacheManager 둘 다 bean등록하게 되면 오류가 생길 수 있어.
따라서
@Bean
@Primary
public CacheManager redisCacheManager() {
return RedisCacheManager.builder(...).build();
}
@Cacheable(cacheManager = "concurrentMapCacheManager", value = "user", key = "#id")
public User getFromJvm(Long id) { ... }
@Cacheable(cacheManager = "redisCacheManager", value = "user", key = "#id")
public User getFromRedis(Long id) { ... }
하는 걸로 어떤 캐시 매니저를 사용할지 직접적으로 명시해줄 수 있지.