스프링 캐시 정리를 토대로 실제로 적용해보자.
스터디 목록은 모든 유저가 다 같은 화면을 볼 것이다. 자주, 반복적으로 조회되는 쿼리로 캐시적용을 통해 조회 성능을 개선하고자 했다.
스프링 캐시
+ 스프링 레디스
의 조합으로 스터디방 목록을 캐시 해보겠다.
implementation("org.springframework.boot:spring-boot-starter-data-redis")
implementation("org.springframework.boot:spring-boot-starter-cache")
private const val PREFIX_OF_CACHE = "API::"
private const val LONG_TERM_CACHE = "longTerm"
private const val SHORT_TERM_CACHE = "shortTerm"
@Configuration
class CacheConfig {
@Bean
fun redisCacheConfiguration(): RedisCacheConfiguration {
return RedisCacheConfiguration.defaultCacheConfig()
.prefixCacheNameWith(PREFIX_OF_CACHE)
.entryTtl(Duration.ofMinutes(1))
.disableCachingNullValues()
.serializeKeysWith(keySerializer)
.serializeValuesWith(valueSerializer)
}
@Bean
fun redisCacheManagerBuilderCustomizer(): RedisCacheManagerBuilderCustomizer? {
return RedisCacheManagerBuilderCustomizer { builder: RedisCacheManagerBuilder ->
builder
.withCacheConfiguration(
SHORT_TERM_CACHE,
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(1))
.disableCachingNullValues()
.serializeKeysWith(keySerializer)
.serializeValuesWith(valueSerializer)
)
.withCacheConfiguration(
LONG_TERM_CACHE,
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(2))
.disableCachingNullValues()
.serializeKeysWith(keySerializer)
.serializeValuesWith(valueSerializer)
)
}
}
private val keySerializer
get() = RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string())
private val valueSerializer
get() = RedisSerializationContext.SerializationPair.fromSerializer(
GenericJackson2JsonRedisSerializer(
redisObjectMapper
)
)
private val redisObjectMapper
get() = ObjectMapper()
.registerModules(KotlinModule.Builder().build(), JavaTimeModule())
.activateDefaultTyping(
BasicPolymorphicTypeValidator.builder().allowIfBaseType(Any::class.java).build(),
ObjectMapper.DefaultTyping.EVERYTHING)
}
설정을 추가한다.
API::
를 사용했다.shortTerm
과 longTerm
으로 나누었다.InvalidDefinitionException
이 발생하는 문제가 있었다. 해당 문제를 해결하기 위한 방법 중 하나가 kotlinModule을 등록하는 것이다. redisObjectMapper에 정의된 objectMapper를 설정에 등록해 주었다.@Cacheable(cacheNames = ["shortTerm"])
fun getStudyRoomList(request: StudyRoomListRequest): StudyRoomListResponse? {
val findStudyRoomList = studyRoomQueryRepository.findStudyRoomList(request.studyRoomSearch, request.studyRoomId, request.pageSize)
return StudyRoomListResponse(findStudyRoomList?.map{SimpleStudyRoomDto.of(it)} ?: null)
}