티스토리 뷰

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 설정과 적절한 키 네이밍 컨벤션은 캐시 효율성을 높이는 핵심 요소입니다.
  • 프록시 기반 동작과 메모리 관리에 대한 주의사항을 숙지해야 합니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2026/05   »
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
31
글 보관함