- Spring Cache Annotation2023년 06월 04일
- starryeye
- 작성자
- 2023.06.04.:13
Spring Framework 에서 제공하는 Cache 어노테이션에 대해 알아보자..
들어가기 앞서 Spring Cache 에 대해 간단하게 알아보자
Spring Cache
애플리케이션의 캐싱 동작을 어떤 캐시 라이브러리를 사용하던지..
일관된 방식으로 적용되도록 관리한다에 목적이 있다.
Spring Cache 는 Spring Framework 의 일부로 제공되는 모듈이며,
캐싱 로직을 비즈니스 로직으로부터 분리(관심사 분리)하여 코드를 깔끔하게 유지할 수 있도록
도와주는 추상화 계층이다.
참고>
Spring Data Redis 의 RedisTemplate 은 Redis 와 상호작용하기 위한 템플릿 클래스이다.
Redis 서버와 통신하며, 데이터의 실제 연산(저장, 검색 등)을 제공해준다.
Redis 데이터 구조를 직접 다양하게 활용하기 쉽다.
Spring Cache 의 대표적 추상화 인터페이스
1. CacheManager 인터페이스
캐시 인스턴스를 관리하고 제공하는 메인 인터페이스이다.
해당 인터페이스의 구현체는 실제 캐싱 기능을 구현한다.
(TTL 등을 설정해볼 수 있다.)
(redis 구현체 : RedisCacheManager)
2. Cache 인터페이스
캐시 저장소에 대한 인터페이스이다.
get. put, evict 와 같은 메서드를 제공한다.
(캐싱 전략을 적용하기 위함이다.. 다양한 데이터 구조를 활용할 수 없음)
(redis 구현체 : RedisCache)
-> RedisCache 는 캐싱 동작을 정의할 때, RedisTemplate 을 사용하여 통신 및 연산을 한다.
3. KeyGenerator 인터페이스
사용자가 원하는 키 생성 로직을 구현하고 적용할 때 사용할 수 있다.
4. @Cacheable, @CachePut, @CacheEvict 등..
캐싱 동작을 선언적으로 지정하는 어노테이션이다.
(밑에 따로 빼서 구체적으로 다룰 것이다.)
Spring Cache 구현체
위에서 확인한 인터페이스들에 대한 구현체가 필요하다..
spring-boot-starter-data-redis, spring-data-redis 등과 같이..
사용할 캐시 라이브러리를 추가하면
구현체가 등록된다.
Spring Cache 에서 제공하는 Annotation 과 캐싱 전략
캐싱 동작을 선언적으로 지정하여
개발자가 직접 구현하지 않아도 되도록 해준다.
이를 활용하여, 캐싱 전략도 편하게 이용하거나 구현해볼 수 있다.
Spring 의 프록시 기반 AOP 를 사용하여 동작한다.
대표적인 어노테이션들..
1. @Cacheable
메서드가 반환하는 값을 캐시에 저장한다.
만약 캐시에 동일한 키의 값이 이미 존재하면,
메서드는 실행되지 않고 캐시된 값을 반환한다.
해당 방식은 캐싱 전략 중 Cache-Aside 방식이다.
예시
@Service public class MyService { @Cacheable(value = "myCache", key = "#id") public MyObject findById(Long id) { // 시간이 오래 걸리는 조회 로직 } }
Redis 를 사용할 경우, 실제 Key 는 myCache::123 이며 (파라미터 id 가 123 일때)
Value 는 MyObject 이다.
참고>
Spring Cache 의 경우, 반환 값의 타입에 따라 특정 Redis Data Type 으로 저장하지 않는다.
반환 값을 직렬화(바이트 배열로 변환) 하여 Redis 에 저장한다.
Spring Cache 는 기본적으로 Java Serialization 을 사용하여 객체를 직렬화한다.
따라서, 모든 Java 객체를 직렬화할 수 있다.
그래서..
반환 타입이 int, Objet 등 어떤 것이든 상관없이, 그 값을 직렬화 하여 Redis 에 저장한다.
직렬화 된 값은 Redis 에서 String 타입으로 저장된다.
-> 따라서 Spring Cache 를 사용하는 것은 RedisTemplate 을 직접 이용하여
다양한 Redis Data Type 을 사용하는 것과는 목적이 좀 다르다..
그런데..
다른 직렬화 방법도 사용할 수 있다. (기본 방법이 바이트 배열로 변환)
RedisTemplate<string, object> 타입의 빈을 CacheManager 빈에 넣어주고 직접 등록하면서,
setValueSerializer 메서드를 이용해보자..
JSON 직렬화 방법을 사용하면, Redis 에 JSON 문자열로 저장된다.
(이러면, Redis 에서 직관적으로 캐시 값을 확인 할 수 있다.)
2. @CachePut
메서드가 반환하는 값을 캐시에 "항상" 저장한다.
메서드가 "항상" 실행되고 그 결과가 캐시에 저장되는 방식이다.
주로 데이터를 업데이트하는 메서드에 사용된다.
이를 이용하여 여러 캐싱 전략을 구현해볼 수 있다.
- 메서드 내에서 반환 값을 DB 에도 저장하면
캐싱 전략 중, Write-Through 전략에 해당한다.
- @Scheduled 어노테이션을 활용하여 batchUpdate 메서드로
DB 에 일정 주기마다 저장하면 캐싱 전략 중, Write-Back 전략에 해당한다.
예시
@Service public class MyService { @CachePut(value = "myCache", key = "#object.id") public MyObject update(MyObject object) { // 객체를 업데이트하고 반환하는 로직 return object; } }
3. @CacheEvict
캐시에서 특정 값을 제거하는 동작이다.
메서드 실행 후 해당 어노테이션에 지정된 키에 해당하는 캐시를 삭제한다.
주로 데이터를 삭제하는 메서드에 사용된다.
예시
@Service public class MyService { @CacheEvict(value = "myCache", key = "#id") public void deleteById(Long id) { // id에 해당하는 객체를 삭제하는 로직 } }
4. @Caching
@Cacheable, @CachePut, @CacheEvict 3가지의 복수 캐시 연산을 그룹화 하는데 사용된다.
복수의 어노테이션 수행 우선순위
1st. @Cacheable
메서드가 호출될 때 캐시를 먼저 확인한다.
캐시에 지정된 키가 존재하면, 캐시된 값을 반환하고 메서드 실행을 생략한다.
캐시에 지정된 키가 존재하지 않으면 다음 단계로 넘어간다.
2nd. 메서드 실행
메서드를 수행하고 반환 값은 다음 단계의 어노테이션에 사용된다.
3rd. @CacheEvict
지정된 키에 해당하는 캐시를 제거한다.
4th. @CachePut
메서드 반환 값을 캐시에 저장한다.
5th. 메서드가 최종적으로 종료되고 값이 반환
예시
@Service public class MyService { @Caching(evict = @CacheEvict(value = "myCache", key = "#id"), put = @CachePut(value = "myCache", key = "#result.id")) public MyObject updateAndEvict(Long id, MyObject object) { // 객체를 업데이트하고 반환하는 로직 return object; } }
우선순위에 따라..
먼저 메서드를 수행한다.
그다음 @CacheEvict 에서 지정한 Key 의 캐시를 삭제한다.
그다음 @CachePut 에서 지정한 Key 의 캐시를 메서드 반환 값으로 저장한다.
그다음 메서드가 종료된다.
5. @CacheConfig
다른 어노테이션들과 다르게 클래스 레벨에 적용된다.
해당 클래스의 모든 캐싱 어노테이션에 공통적으로 적용될 설정을 지정할 수 있다.
예시
@Service @CacheConfig(cacheNames = "myCache") public class MyService { @Cacheable(key = "#id") public MyObject findById(Long id) { // 조회 로직 } @CacheEvict(key = "#id") public void deleteById(Long id) { // 삭제 로직 } }
'Spring > DB, Cache 연동' 카테고리의 다른 글
JPA Entity Default Constructor (1) 2023.06.07 JPA Merge, Dirty Check (0) 2023.06.06 Spring Data Redis (0) 2023.06.03 Spring 의 DB 연동 기술 히스토리 요약 (0) 2023.03.10 JPA 핵심 정리 - 모음 (0) 2023.02.22 다음글이전글이전 글이 없습니다.댓글