RedisCacheConfig.java
@EnableCaching
@Configuration
public class RedisCacheConfig {
@Value("${spring.redis.cache.host}")
private String host;
@Value("${spring.redis.cache.port}")
private int port;
@Value("${spring.redis.cache.password}")
private String password;
@Bean
public RedisConnectionFactory redisCacheConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(host);
config.setPort(port);
config.setPassword(password);
return new LettuceConnectionFactory(config);
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(redisCacheConnectionFactory());
return redisTemplate;
}
@Bean
public RedisCacheConfiguration defaultRedisCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofHours(1L))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
@Bean
public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
return (builder) -> builder
.withCacheConfiguration("products", defaultRedisCacheConfiguration().entryTtl(Duration.ofMinutes(30)));
}
}
@EnableCaching
- 스프링에 AOP로 구현되어있는 캐시 로직을 사용한다.
- 스프링이
CacheManager
인터페이스를 추상화하였기 때문에 RedisCacheManager
, EhCacheManager
등 필요한 CacheManage
로 갈아끼워 사용할 수 있다.
캐시 설정
CacheManager
를 이용해서 Serializer, TTL(Time to Live), key 의 prefix 등을 디테일하게 설정할 수 있다.
RedisCacheManagerBuilderCustomizer
를 사용하여 캐시마다 TTL 등 캐시 정책을 다르게 적용할 수 있도록 하였다.
ProductController.java
@RequestMapping("/products")
@RequiredArgsConstructor
@RestController
public class ProductController {
private final ProductService productService;
@Cacheable(key="#dto.start", value="products")
@GetMapping
public SuccessResponse getProducts(@Valid @ModelAttribute GetProductsRequest dto) {
List<SimpleProduct> products = productService.getProducts(dto);
return SuccessResponse.builder()
.status(StatusEnum.OK)
.message("상품 목록 가져오기 성공")
.data(products)
.build();
}
}
캐시 저장/삭제
- 캐시 저장
@Cacheable
: 캐시가 있으면 캐시의 정보를 가져오고, 없으면 등록한다.
- SpEL(Spring Expression Language) 을 지원한다.
@Cacheable(key="#dto.start", value="products")
- (필자는 사용하지 않았으나)
unless
라는 옵션으로 조건을 걸어줄 수 있으니 참고하기 바란다!
@CachePut
: 무조건 캐시에 저장한다.
- 캐시 삭제
@CacheEvict
: 캐시 데이터와 DB의 불일치성이 발생할 수 있기 때문에 캐시 데이터의 update, delete가 발생할 경우 해당 어노테이션을 적용하여 캐싱 데이터를 제거해야 한다.