Spring/Cache

Spring Cache Abstraction with Spring Boot

Krevis 2023. 11. 14. 13:41

학습 환경: 스프링 부트 3.1.5

0. 이 문서에서 다루는 것

  • 로컬 캐쉬
  • 스프링의 캐쉬 추상화
    • 주요 객체 소개
  • 간단한 예제

1. Cache Providers

스프링은 늘 기술 구현체를 직접 제공하지 않는다. 인터페이스와 서비스 추상화를 제공할 뿐이다.

 

스프링이 지원하는 캐쉬 제공자: https://docs.spring.io/spring-boot/docs/current/reference/html/io.html#io.caching.provider

 

여기서는 로컬 캐쉬를 사용하는 몇 가지만 다뤄보겠다.

  • Simple
  • Generic
  • JCache (JSR-107)

1.1 Simple

https://docs.spring.io/spring-boot/docs/current/reference/html/io.html#io.caching.provider.simple

 

학습 테스트 코드: https://github.com/venzersiz/learn-spring-cache-abstraction/commit/c68bbbaac47b3f43331f88dbf97be359f2b2f4ee

 

용도

  • 테스팅
  • 간단한 캐슁 시나리오

1.1.1 캐쉬를 사용하기 위한 최소한의 준비

의존성 추가

implementation "org.springframework.boot:spring-boot-starter-cache"

위 의존성을 기본으로, 앞으로 캐쉬 라이브러리의 의존성을 추가한다.

 

애너테이션 추가

@SpringBootApplication
@EnableCaching

 

아무런 캐쉬 라이브러리를 추가하지 않으면 SimpleCacheConfiguration 빈이 Auto-configuration(이하 자동 설정)되어, ConcurrentMapCacheManager 빈을 등록한다.

 

자동 등록되는 빈

  • org.springframework.cache.annotation.ProxyCachingConfiguration
  • org.springframework.cache.config.internalCacheAdvisor
  • cacheOperationSource
  • cacheInterceptor
  • org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration
  • cacheManager
  • org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
  • cacheManagerCustomizers
  • cacheAutoConfigurationValidator
  • spring.cache-org.springframework.boot.autoconfigure.cache.CacheProperties

1.1.2 Cache Manager

스프링의 캐쉬 매니저 SPI

 

주요 메서드

  • @Nullable Cache getCache(String name)
    • 캐쉬는 이름을 가질 수 있고 null일 수 있음을 알 수 있다.
    • 캐쉬는 지연 생성될 수 있음

1.1.3 Cache

공통적인 캐쉬 작업을 정의한 인터페이스

 

메서드

  • String getName()
    • 캐쉬는 (논리적인) 이름을 가진다
  • Object getNativeCache()
    • Cache Provider를 반환한다
  • ValueWrapper get(Object key)
    • 키로 값을 가져온다. 키는 꼭 문자열일 필요는 없으며, 값은 래핑되어있다.
    • 해당 키로 매핑된 것이 없다면 null을 반환한다.
    • 매핑된 것이 있다면 그 값을 내포한 ValueWrapper 객체를 반환한다. 값 자체는 null일 수 있다.
    • ValueWrapper 함수형 인터페이스를 제공하는 이유는 키가 매핑된 것이 없어서 null인지 값 자체가 null인지를 구분할 수 있도록 해주기 위해서인 듯 하다.
  • void put(Object key, @Nullable Object value);
    • 값은 null일 수 있다.
  • void evict(Object key)
  • ...

1.1.4 ConcurrentMapCacheManager

로컬 메모리에 캐슁하는 ConcurrentHashMap<String, ConcurrentMapCache> 타입의 캐쉬 저장소를 사용한다.

 

Cache getCache(String name) 메서드로 캐쉬 객체를 가져올 때 지정한 이름의 캐쉬를 기정의하지 않은 경우 새로 생성하여 반환한다. 하지만 spring.cache.cache-names 프라퍼티에 쉼표 구분으로 사용할 캐쉬명을 지정한 경우, 존재하지 않는 캐쉬 조회 시 null 반환한다.

1.2 Generic

https://docs.spring.io/spring-boot/docs/current/reference/html/io.html#io.caching.provider.generic

 

학습 테스트 코드: https://github.com/venzersiz/learn-spring-cache-abstraction/commit/c61dd1b1306bd45ff64a1b088a1670611fc88042

 

org.springframework.cache.Cache 타입의 빈을 직접 등록하면 동작하며, SimpleCacheManager가 사용된다.

 

용도

  • 테스팅
  • 간단한 캐슁 정의

 

자동 등록되는 빈

  • org.springframework.cache.annotation.ProxyCachingConfiguration
  • org.springframework.cache.config.internalCacheAdvisor
  • cacheOperationSource
  • cacheInterceptor
  • org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
  • cacheManager
  • org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
  • cacheManagerCustomizers
  • cacheAutoConfigurationValidator
  • spring.cache-org.springframework.boot.autoconfigure.cache.CacheProperties

1.2.1 SimpleCacheManager

등록된 Cache 타입의 빈을 컬렉션으로 가지며, 로컬 메모리에 캐슁하는 ConcurrentHashMap<String, Cache> 타입의  캐쉬 저장소를 사용한다.

1.3 JCache (JSR-107)

https://jcp.org/en/jsr/detail?id=107

자바 진영의 캐쉬 추상화 표준인 Java Temporary Caching API

 

클래스패스에 JSR-107 준수 캐슁 라이브러리가 존재하면 동작한다.

  • EhCache 3
  • Hazelcast
  • Infinispan
  • Caffeine
  • Apache JCS

 

javax.cache 패키지의 클래스도 필요하기 때문에 JSR107 API and SPI 의존성이 필요하다. spring-boot-starter-cache 부트 스타터 의존성을 추가하면 알아서 추가된다.

 

EhCache 3를 사용한다면, Eh107CacheManager가 사용되며 JCacheCacheManager는 래퍼로서 사용된다

https://www.ehcache.org/

 

자동 등록되는 빈

  • org.springframework.cache.annotation.ProxyCachingConfiguration
  • org.springframework.cache.config.internalCacheAdvisor
  • cacheOperationSource
  • cacheInterceptor
  • org.springframework.cache.jcache.config.ProxyJCacheConfiguration
  • org.springframework.cache.config.internalJCacheAdvisor
  • jCacheInterceptor
  • jCacheOperationSource
  • org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
  • cacheManager
  • jCacheCacheManager
  • org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
  • cacheManagerCustomizers
  • cacheAutoConfigurationValidator
  • spring.cache-org.springframework.boot.autoconfigure.cache.CacheProperties

1.3.1 Eh107CacheManager

로컬 메모리에 캐슁하는 ConcurrentMap<String, Eh107Cache> 타입의  캐쉬 저장소를 사용한다.

 

CacheManager 커스터마이징 방법은 2가지가 있다.

  • spring.cache.cache-names 프라퍼티를 통해 사용할 캐쉬를 정의한다. javax.cache.configuration.Configuration 빈을 재정의한다.
  • JCacheManagerCustomizer 빈들을 통해 완전한 커스터마이징 가능하다.

 

용도

  • JVM 내 캐슁
    • 일반적으로 Ehcache가 가장 많이 쓰이는 듯 하다.
  • 로컬 캐슁
    • 글로벌 캐슁을 원한다면 레디스를 사용하자.

학습 테스트 코드: https://github.com/venzersiz/learn-spring-cache-abstraction/commit/6f87642ff5505f84cbf45ca507661a4b477e607c

1.3.2 Cache expiry, TTL

캐쉬는 기본적으로 만료되지 않는다. 캐쉬별 만료시간을 설정하여 캐쉬를 자동으로 삭제시킬 수 있다.

 

학습 테스트 코드: https://github.com/venzersiz/learn-spring-cache-abstraction/commit/4f70f734137db11c691ac0ee334010d072e06026

1.3.3 Value as object

지금까지는 캐쉬에 단순한 값만 저장하였는데, 객체도 저장할 수 있을까? 당연히 가능하다. 단, 객체는 직렬화되어야 하므로 Serializable 인터페이스를 구현해야 한다.

 

아직까지는 로컬 캐쉬를 사용하다 보니 직렬화에 어려움을 겪지 않는다.

 

학습 테스트 코드: https://github.com/venzersiz/learn-spring-cache-abstraction/commit/400e168a2e5df78305e88508d69321b2a39eb7aa

1.3.4 Declarative annotation-based caching

스프링이 제공하는 애너테이션을 사용해 선언형으로 메서드의 반환값을 캐슁할 수 있다. 실무에서는 이 방식이 가장 많이 쓰인다.

 

학습 테스트 코드: https://github.com/venzersiz/learn-spring-cache-abstraction/commit/6efdd0b057c1a0dd0578693f2eb62c4a9f7c965d

 

참고

'Spring > Cache' 카테고리의 다른 글

Spring > Cache > @Cacheable로 저장되는 데이터 자료구조  (0) 2025.05.08
Redis cache with Spring Boot  (0) 2023.11.17