- Spring Cache 사용기록2026년 02월 22일 19시 58분 37초에 업로드 된 글입니다.작성자: do_hyuk728x90반응형
1) 개발 환경 구성
개발 환경 버전
java 17 Spring Boot 3.1.2 빌드관리도구 Maven 3.11.0 개발 툴 IntelliJ IDEA 2025.3.2 spring-boot-starter-cache 4.1.0-M1 com.github.ben-manes.caffeine 3.2.3 2) API 캐싱, Spring Boot Cache 이해
💡API Caching - API의 호출에 따라서 캐시를 이용하여 '서버의 부하를 줄이고 API 성능을 최적화' 하여 '응답시간을 단축' 시키는 역할 수행 💡Spring Boot Starter Cache - 자주 사용되는 데이터를 '캐시 메모리'에 저장하여 빠른 검색을 가능하게 하는 기능 제공 - 해당 캐시에 저장되는 데이터를 CacheManager를 통하여 메모리 뿐만 아니라 디스크, 데이터베이스, 클라우드 서비스와 같은 '다른 저장소'에도 저장이 가능[1] Spring Boot Cache 사용 목적
💡Spring Boot Cache 사용목적 - API에서 Database로 부터 데이터를 조회하는 경우 '동일한 데이터를 반복하여 조회' 해옴으로써 '불필요한 일을 반복하는 문제'가 발생 - 이에 따라서 API 캐싱을 통해서 DB 로부터 반복적으로 데이터를 조회해오는 일에 대해 최초 데이터만 직접 조회해 온 뒤 이후에는 캐시에서 데이터를 조회해 오는 처리를 수행함으로써 API의 성능을 울리며 응답시간을 단축하는 효율성을 가져온다.[2] Spring Boot Cache 사용처
외부 API로 부터 특정 이벤트 발생에 대한 callback 요청을 히스토리에 저장할 때 사용 예시) callback : 'ON_AIR' -> db : ON_AIR = '송출 시작' -> 히스토리 : '송출 시작' 저장3) Spring Boot Cache 어노테이션
Annotation 설명
@EnableCaching Spring Boot Cache를 사용하기 위해 '캐시 활성화'를 위한 어노테이션 @CacheConfig 캐시정보를 '클래스 단위'로 사용하고 관리하기 위한 어노테이션 @Cacheable 캐시정보를 메모리 상에 ‘저장’하거나 ‘조회’ 해오는 기능을 수행하는 어노테이션 @CachePut 캐시 정보를 메모리상에 '저장'하며 존재 시 갱신하는 기능을 수행하는 어노테이션 @CacheEvict 캐시 정보를 메모리상에 '삭제'하는 기능을 수행하는 어노테이션 @Caching 여러 개의 ‘캐시 어노테이션’을 ‘함께 사용’할 때 사용하는 어노테이션 [1] CacheManager 종류
CacheManager 캐시 저장 위치 설명
ConcurrentMapCacheManager 메모리 상에 캐시 저장 ConcurrentHashMap 기반 캐시 구현 CaffeineCacheManager 메모리 상에 캐시 저장 Caffeine 기반 캐시 구현체 SimpleCacheManager 메모리 상에 캐시 저장 단순 캐시 구현체 EhCacheCacheManager 디스크 또는 데이터베이스에 저장 Ehcache 기반 캐시 구현체 HazelcastCacheManager 메모리 상에 캐시 저장 Hazelcast 기반 캐시 구현 InfinispanCacheManager 메모리 상에 캐시 저장 Infinispan 기반 캐시 구현체 RedisCacheManager Redis 내의 데이터베이스에 저장 Redis 기반 캐시 구현체 CouchbaseCacheManager Couchbase 내의 데이터베이스에 저장 Couchbase 기반 캐시 구현 GemfireCacheManager 자체 저장소에 저장 GemFire 기반 캐시 구현체 CoherenceCacheManager 자체 저장소에 저장 Oracle Coherence 기반 캐시 구현체 CaffeineCacheManager 를 선택한 이유
요약하자면 `읽기 속도` / `쓰기 속도` / `읽기-쓰기 속도` 모두 제일 뛰어남 따로 'com.github.ben-manes.caffeine' 의존성을 주입해서 사용해야 함출처: https://github.com/ben-manes/caffeine/wiki/Benchmarks
- CacheConfig.class
@EnableCaching -> 캐시 활성화 @Configuration public class CacheConfig { @Bean public CacheManager cacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager("callbackMap"); cacheManager.setCaffeine(caffeineConfig()); return cacheManager; } @Bean public Caffeine<Object, Object> caffeineConfig() { return Caffeine.newBuilder() .maximumSize(100) .expireAfterAccess(300, TimeUnit.SECONDS) .recordStats(); } } - Service.class
@Cacheable(value = "callbackMap", key = "#channelType", unless = "#result = null") public Map<String, String> getCallbackMap(String channelType) { return liveCallbackCodeRepository.findAllByLclccChType(channelType); } - value : 사용할 캐시 이름 - key : 캐시에서 조회할 키값 - unless : result 값은 메서드 return 값으로 db에 값이 없어서 null을 반환하기 전 unless는 null = null로 true이기 때문에 캐시 저장 X unless가 false 면 캐시에 저장@Cacheable(value = "callbackMap", key = "#channelType") public Map<String, String> getCallbackMap(String channelType) { return liveCallbackCodeRepository .findAllByLclccChType(channelType) .stream() .collect(Collectors.toMap( LiveCallbackCodeEntity::getLclccEventCode, LiveCallbackCodeEntity::getLclccDesc )); } @CachePut(value = "callbackMap", key = "#channelType") public Map<String, String> refreshCallbackMap(String channelType) { return liveCallbackCodeRepository .findAllByLclccChType(channelType) .stream() .collect(Collectors.toMap( LiveCallbackCodeEntity::getLclccEventCode, LiveCallbackCodeEntity::getLclccDesc )); } @CacheEvict(value = "callbackMap", key = "#channelType") public void evictCallbackMap(String channelType) {} public CacheStatsResponse getCallbackDescStats(String cacheName) { CaffeineCache cache = (CaffeineCache) cacheManager.getCache(cacheName); if (cache == null) { throw new BadRequestException(ErrorMessage.NOT_FOUND_CACHE); } CacheStats stats = cache.getNativeCache().stats(); return CacheStatsResponse.builder() .requestCount(stats.requestCount()) .hitCount(stats.hitCount()) .missCount(stats.missCount()) .hitRate(stats.hitRate()) .missRate(1.0 - stats.hitRate()) .evictionCount(stats.evictionCount()) .build(); }
Spring AOP가 캐시 사용을 확인하기 때문에 캐싱 메서드를 사용하기 위해서는 따른 클래스에서 호출해야함
728x90반응형'Spring' 카테고리의 다른 글
[트러블 슈팅] 다중 인스턴스일 때 동시성 문제 해결 (0) 2026.03.08 [트러블 슈팅] JPA UPDATE 벌크 연산 후 조회 안됨 (0) 2026.02.01 [트러블 슈팅] 재배포 없이 스케줄링 날짜 변경하기 (0) 2026.01.31 [트러블 슈팅] JWT 유효기간보다 빨리 만료되는 문제 해결 (0) 2026.01.11 Chained Transaction Manager deprecated (0) 2026.01.04 댓글 - CacheConfig.class