학습 환경: 스프링 부트 3.1.5
0. 이 문서에서 다루는 것
- 글로벌 캐쉬
- 스프링의 캐쉬 추상화
- 주요 객체 소개
- 간단한 예제
1. Redis 서버 설치 및 실행
애플리케이션에서 Embedded 레디스 서버를 사용할 수도 있지만 실제 데이터가 어떻게 들어가는지 눈으로 보는 것도 중요하다.
2023.11.15 - [Redis] - Redis 서버 설치
2. Cache Provider > Redis
https://docs.spring.io/spring-boot/docs/current/reference/html/io.html#io.caching.provider.redis
3. 레디스 캐쉬를 사용하기 위한 최소한의 준비
의존성 추가
implementation "org.springframework.boot:spring-boot-starter-data-redis"
애너테이션 추가
@SpringBootApplication
@EnableCaching
RedisAutoConfiguration 빈이 Auto-configuration(이하 자동 설정)되어, RedisCacheManager 빈을 등록한다.
자동 등록되는 빈
- org.springframework.boot.autoconfigure.data.redis.LettuceConnectionConfiguration
- redisConnectionFactory
- org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
- redisConnectionDetails
- redisTemplate
- stringRedisTemplate
- spring.data.redis-org.springframework.boot.autoconfigure.data.redis.RedisProperties
- org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
- org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration
- reactiveRedisTemplate
- reactiveStringRedisTemplate
- org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
- redisIndexConfiguration#0
- redisKeyspaceConfiguration#0
- redisMappingConfiguration#0
- redisCustomConversions
- redisReferenceResolver
- redisConverter
- redisKeyValueAdapter
- redisKeyValueTemplate
- data-redis.repository-aot-processor#0
4. RedisCacheManager
기본적으로 첫 쓰기 작업 시에 RedisCache를 생성한다.
학습 테스트 코드: https://github.com/venzersiz/learn-spring-redis/commit/21b5b66a8bfcac2655a26f895e7191bc5eb77882
5. Value as object
레디스는 로컬 캐쉬가 아닌데 객체를 그냥 저장할 수 있을까?
학습 테스트 코드: https://github.com/venzersiz/learn-spring-redis/commit/23627c8b202792fceb5bccffda3f516e5fb16886
가능하다. 하지만 인간이 읽기 어려운 바이너리 형태로 값이 저장된다. (JdkSerializationRedisSerializer)
캐쉬를 쓰고 읽는데는 문제가 없다. 하지만 캐슁된 데이터를 확인해야 될 때가 가끔 발생한다. 뿐만 아니라 자바 네이티브 직렬화는 보안에 좋지 않다. 스프링에서는 JSON 형식을 사용할 것을 강하게 권장하고 있다.
6. RedisSerializer
https://docs.spring.io/spring-data/redis/docs/current/reference/html/#redis:serializer
키, 값, Hash의 형식은 RedisSerializer가 담당한다. 예를 들어 객체를 String으로 직렬화하여 저장하길 원한다면 StringRedisSerializer를 사용하면 된다.

6.1 RedisCacheConfiguration
커스텀 RedisCacheConfiguration 빈을 등록하면 기본 설정을 변경할 수 있다. 사용하고자 하는 RedisSerializer를 설정하자.
학습 테스트 코드: https://github.com/venzersiz/learn-spring-redis/commit/9b73c334998947db774cbffa827e7f93fece5430
6.2 JSON 형식
6.2.1 Jackson2JsonRedisSerializer
이 인스턴스를 생성할 때 생성자에 데이터 타입을 전달해야 한다. 보통은 빈을 싱글턴으로 만들어 재활용하기 때문에 활용도가 떨어진다. 그렇다고 타입을 Object로 정의하면 값을 가져올 때 LinkedHashMap 타입으로 가져온다. 나는 데이터 모델로 맵을 쓰는 것을 좋아하지 않기 때문에 사용하지 않을 것이다.
6.2.2 GenericJackson2JsonRedisSerializer
Jackson 2 기반이며 위의 단점이 없다. RedisSerializer 인터페이스의 정적 팩터리 메서드로 이 인스턴스를 제공하는 것을 보면, 스프링에서도 위의 것보다는 권장하는 것 같다.
static RedisSerializer<Object> json() {
return new GenericJackson2JsonRedisSerializer();
}
아래 모델에 대한
class User {
Long seq;
String name;
List<Address> addresses;
}
class Address {
String name;
}
직렬화 결과는 다음과 같다.
{
"@class": "learn.redis.annotation.domain.model.User",
"seq": 1,
"name": "김백세",
"addresses": [
"java.util.ImmutableCollections$List12",
[
{
"@class": "learn.redis.annotation.domain.model.Address",
"name": "주소1"
},
{
"@class": "learn.redis.annotation.domain.model.Address",
"name": "주소2"
}
]
]
}
특이한 점은 모델에는 없는 @class라는 필드다. 스프링이 이런 구조를 만드는 것은 아니다. Jackson의 기본 Default typing이 적용되어 있기 때문이다. 다형성을 지원하기 위해서는 역직렬화 시 사용될 타입 정보가 필요하다.
참고: 2023.11.10 - [JSON/Jackson] - Jackson > Basic
학습 테스트 코드: https://github.com/venzersiz/learn-spring-redis/commit/5db7aa0cf689b78231cfb76a96269db6a1d22cfb
7. GenericJackson2JsonRedisSerializer 사용 시 유의사항
예를 하나 들어보겠다. 캐쉬를 저장하는 애플리케이션과 캐쉬를 조회하는 애플리케이션이 다른 경우, 캐쉬를 조회하는 애플리케이션의 모델의 클래스 경로가 캐쉬를 저장하는 애플리케이션의 모델의 클래스 경로와 상이할 때도 정상적으로 역직렬화가 될까?
학습 테스트 코드: https://github.com/venzersiz/learn-spring-redis/commit/5db7aa0cf689b78231cfb76a96269db6a1d22cfb
안 된다.
그럼 어떻게 해야할까? 문제는 패키지명을 포함한 클래스명을 담고 그걸 역직렬화 시 그대로 사용하기 때문이니, 물리적인 방식을 사용하지 말아야 한다.
7.1 논리적인 타입 식별자를 사용하도록 커스터마이징
우선 이 글을 읽자.
2023.11.13 - [JSON/Jackson] - Jackson > Intermediate > TypeIdResolver
커스텀 TypeIdResolver를 등록해 논리적인 타입 식별자를 사용하면 제약이 모두 사라지게 된다.
학습 테스트 코드: https://github.com/venzersiz/learn-spring-redis/commit/176060f38f27024f84aad16b7f20bce39153df55
8. Declarative annotation-based caching
위 방식이 실무에서 많이 사용하는 @Cacheable에도 잘 적용이 될까? 된다.
학습 테스트 코드: https://github.com/venzersiz/learn-spring-redis/commit/e64a2e1b7ce90533509330b511c0ada77e2e9ab7
9. Cache Key
기본 레디스 캐쉬 키는 CacheKeyPrefix 인터페이스에 의해 생성된다.
정의한 캐쉬명 + 구분자(::) + 정의한 캐쉬키
레디스 키의 명명규칙은 소문자 그리고 콜론(:)의 조합이다.
캐쉬명이 someapi:user이고, 캐쉬 키가 3이라면 someapi:user::3으로 캐쉬 키가 생성된다.
학습 테스트 코드: https://github.com/venzersiz/learn-spring-redis/commit/59e5b617ce4afb66320f3e1e491b249573684746
10. RedisTemplate
애너테이션을 사용한 선언형 프로그래밍이 아닌 명령형으로 직접 레디스 명령을 내릴 때 사용된다. 중요한 점은 캐쉬 관련 설정들이 RedisTemplate에는 적용되지 않는다는 것이다. 즉, 경우에 따라 여러 인스턴스를 만들어서 사용해야 한다는 것.
특별한 일이 없다면 굳이 사용할 일은 없을 것 같다.
응용
1. 프라퍼티 설정 기반으로 캐쉬별 TTL 적용
레디스 전역 TTL 설정은 spring.cache.redis.time-to-live 프라퍼티를 설정하여 적용할 수 있다. 캐쉬별 TTL 설정을 위해서는 각 캐쉬별로 자바 코드 설정이 필요하다. @Cacheable에서는 아쉽게도 TTL 설정을 지원하지 않는다.
전역 설정처럼 각 캐쉬별로 TTL 설정을 할 수 있으면 편할 것이다.
학습 테스트 코드: https://github.com/venzersiz/learn-spring-redis/commit/42c3c0614b663dc88ca8636a5660c883d081bcd8
나중에 읽을 거
- https://jiwondev.tistory.com/282
- https://icthuman.tistory.com/entry/Redis-%EC%BA%90%EC%8B%9C%EC%82%AC%EC%9A%A9%EC%8B%9C-key
- https://medium.com/@estebanbett/springboot-caching-extension-library-for-centralized-configuration-1a12d3427d6e
- https://velog.io/@choidongkuen/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-Redis-%EC%A7%81%EB%A0%AC%ED%99%94-%EB%B0%A9%EB%B2%95%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C
- https://github.com/binghe819/TIL/blob/master/Spring/Redis/redis%20serializer/serializer.md
'Spring > Cache' 카테고리의 다른 글
| Spring > Cache > @Cacheable로 저장되는 데이터 자료구조 (0) | 2025.05.08 |
|---|---|
| Spring Cache Abstraction with Spring Boot (0) | 2023.11.14 |