티스토리 뷰
Spring Cache란?
Spring Cache는 Spring Framework에서 제공하는 다양한 캐시 구현체(Redis, Ehcache, Caffeine 등)를 공통된 API로 사용할 수 있게 해주는 추상화 계층입니다. 어떤 캐시 저장소를 사용하던 동일한 방식으로 캐싱 전략을 적용할 수 있습니다.
Spring 3.1, Spring Boot 1.0 이상 부터 Spring Cache를 사용할 수 있습니다.
Spring Cache 적용
1. 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-cache'
2. 캐시 설정 활성화
@Configuration
@EnableCaching
public class CacheConfig {
// 기본 CacheManager 사용 시 따로 설정 생략 가능
}
Cache 설정에서는 사용하는 캐시 저장소에 맞는 CacheManager를 등록할 수 있습니다.
CacheManager는 캐싱과 관련된 설정을 총괄하며, TTL, 최대 저장 개수 등 캐시 동작 방식을 전반적으로 제어하는 역할을 합니다.
| 캐시 저장소 | CacheManager 구현체 | 설명 |
|---|---|---|
| 메모리 (Caffeine) | CaffeineCacheManager |
로컬 캐시, JVM 안에서만 |
| 분산 (Redis) | RedisCacheManager |
외부 Redis를 통한 분산 캐시 |
| Ehcache | EhCacheCacheManager |
XML/Java 설정 기반 디스크 + 메모리 |
| ConcurrentMap | ConcurrentMapCacheManager |
테스트용 기본 메모리 캐시 (Spring 기본값) |
3. 구현 예제
간단하게 어노테이션만 사용하면 캐시를 추가 삭제할 수 있습니다.
@Service
public class MyService {
@Cacheable(value = "greetings", key = "#name")
public String sayHello(String name) {
System.out.println("⏱ 실제 메서드 실행됨!");
return "Hello, " + name;
}
@CacheEvict(value = "greetings", key = "#name")
public void clearGreeting(String name) {
System.out.println("🧹 캐시 삭제됨!");
}
}
Spring Cache 상세 기능
1. @EnableCaching
@EnableCaching은 캐시 기능을 활성화하는 어노테이션입니다. 스프링 설정 클래스나 메인 클래스에 사용할 수 있습니다.
@Configuration
@EnableCaching
public class CacheConfig {
// Caffeine 로컬 캐시 설정 예시
@Bean public CacheManager caffeineCacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(
Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(30, TimeUnit.MINUTES)
);
return cacheManager;
}
}
2. @Cacheable
@Cacheable은 요청한 데이터가 캐시에 있으면 캐시에서 가져오고, 없으면 DB에서 가져와 캐시에 저장해두는 역할을 합니다.
기본 사용법
@Cacheable(value = "greetings", key = "#name")
public String sayHello(String name) {
System.out.println("실제 메서드 실행됨");
return "Hello, " + name;
}
// value 만 지정하는 축약 표현
@Cacheable("greetings")
public String sayHello(String name) {
// key는 자동으로 파라미터 기준 생성
}
#name은 파라미터 이름과 일치하는 값을 캐시 키로 사용한다는 의미입니다.
주요 속성
| 속성 | 필수 | 기본값 | 예시 | 설명 |
|---|---|---|---|---|
value |
✅ | - | "greetings" |
캐시 이름 |
key |
❌ | 파라미터 기반 자동 생성 | "#name" |
캐시 키 |
condition |
❌ | - | "#age > 18" |
캐싱 조건 |
unless |
❌ | - | "#result.isEmpty()" |
캐싱 제외 조건 |
캐시 키 생성 규칙
단일 파라미터
@Cacheable("users")
public User getUser(String name) { ... }
// 결과: users::junyoung
복수 파라미터
@Cacheable("users")
public User getUser(String name, int age) { ... }
// 결과: users::SimpleKey [junyoung, 30]
조건부 캐싱
// 특정 조건일 때만 캐싱
@Cacheable(value = "users", condition = "#age > 18")
public User getUser(String name, int age) {
// 18세 이상일 때만 캐싱
}
// 결과가 특정 조건일 때 캐싱 제외
@Cacheable(value = "users", unless = "#result.isEmpty()")
public List<User> getUsers() {
// 결과가 비어있지 않을 때만 캐싱
}
캐시 키는 예상치 못한 키 충돌을 야기할 수 있기 때문에 가능하면 명시적인 key 설정이 권장됩니다.
3. @CacheEvict
@CacheEvict는 캐시에 저장된 데이터를 제거할 때 사용하는 어노테이션입니다. 데이터가 변경(수정, 삭제)되었을 때 캐시도 함께 지워줘야 하는 경우 사용합니다.
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
// 전체 캐시 삭제
@CacheEvict(value = "users", allEntries = true)
public void clearAllUsers() {
userRepository.deleteAll();
}
// 여러 캐시 동시 처리
@Caching(evict = {
@CacheEvict(value = "users", key = "#user.id"),
@CacheEvict(value = "userProfiles", key = "#user.id")
})
public void updateUser(User user) {
userRepository.save(user);
}
4. @CachePut
@CachePut는 캐시에 저장된 데이터를 갱신하기 위해 사용하는 어노테이션입니다. DB에 값을 업데이트하고 캐시값을 동기화 하는 목적으로 사용합니다.
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
return userRepository.save(user);
}
5. TTL 설정
캐시 저장소는 메모리 데이터베이스 기반이기 때문에 디스크 보다 사용할 수 있는 용량이 제한됩니다. 따라서 메모리 관리를 위해 다양한 전략들과 TTL을 지정하여 캐싱된 데이터를 관리합니다.
TTL은 어노테이션 레벨에서 설정하는 것이 아니라 CacheManager에서 지정해야 합니다.
1. Java 코드 TTL 설정
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
// 캐시 이름별 TTL 설정
configMap.put("greetings", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5)));
configMap.put("users", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1)));
return RedisCacheManager.builder(connectionFactory)
.withInitialCacheConfigurations(configMap)
.build();
}
}
@Cacheable(value = "greetings")→ 5분 TTL@Cacheable(value = "users")→ 1시간 TTL
2. application.yml TTL 설정
spring:
cache:
type: redis
redis:
time-to-live: 600000 # milliseconds → 10분 TTL
모든 캐시에 동일한 TTL을 적용할 때 사용할 때 사용하는 방법입니다. 캐시 이름별로 다르게 지정하려면 Java 코드 설정이 필요합니다. RedisCacheManager로 TTL을 지정했다면 해당 설정이 우선시됩니다. application.yml의 설정은 기본 설정으로 동작합니다.
캐시 키 네이밍 컨벤션
체계적인 캐시 키 네이밍은 캐시 관리, 모니터링, 디버깅을 효율적으로 만들어줍니다. 일관된 규칙을 통해 캐시 충돌을 방지하고 유지보수성을 높일 수 있습니다.
권장 패턴
// 도메인:엔티티:액션 패턴
@Cacheable("user:profile:#{#userId}")
@Cacheable("product:detail:#{#productId}")
@Cacheable("order:history:#{#userId}")
// 계층적 구조
@Cacheable("api:user:findById")
@Cacheable("db:product:findByCategory")
주의사항
1. 프록시 기반 동작
- 같은 클래스 내부 메서드 호출 시 캐시가 동작하지 않습니다.
@Transactional과 함께 사용 시 순서를 고려해야 합니다.2. 메모리 관리- 캐시 크기와 메모리 사용량을 주기적으로 모니터링해야 합니다.
- 적절한 TTL과 최대 저장 개수 설정이 필요합니다.
요약
- Spring Cache는 다양한 캐시 저장소를 추상화하여 일관된 방식으로 사용할 수 있게 해줍니다.
- @Cacheable, @CacheEvict, @CachePut을 활용한 선언적 캐싱으로 비즈니스 로직과 분리 가능합니다.
- TTL 설정과 적절한 키 네이밍 컨벤션은 캐시 효율성을 높이는 핵심 요소입니다.
- 프록시 기반 동작과 메모리 관리에 대한 주의사항을 숙지해야 합니다.
'라이브러리&프레임워크 > Spring' 카테고리의 다른 글
| JPA 엔티티에서 Setter 대신 Builder 패턴을 사용해야 하는 이유 (0) | 2025.11.10 |
|---|---|
| Spring 개발자를 위한 캐싱 전략: 로컬 캐시부터 Redis 분산 캐시까지 (0) | 2025.07.27 |
| Spring Boot Metric 수집 및 시각화 방법 (Prometheus + Grafana) (0) | 2025.07.20 |
| 동시성 문제와 해결 전략 (비관적 락 vs 낙관적 락) (0) | 2025.05.10 |
| AOP란? (0) | 2025.05.02 |
