개발/Spring Boot

[Spring Boot] Spring Boot Application 을 재시작해도 Spring cache가 초기화 되지 않는 문제 해결

YJ_Lee 2024. 2. 7. 15:33

Introduction

Spring-boot-starter-cache 라이브러리를 사용하던 중 Spring Application 을 재시작해도 캐시가 초기화 되지 않아 빈 DB를 조회해도 Cache 에서 데이터를 꺼내 반환하는 문제가 발생하였다. 심지어 Intellij 를 껏다 켜도 마찬가지였다. 컴퓨터를 재부팅 해야지만 캐시가 초기화 되었다.

 

상식적으로 Spring cache는 Spring Application 내부의 메모리를 사용하는 것일텐데 어떻게 App 이 종료되어도 캐시가 초기화되지 않는 것인가?

Code

Controller

@GetMapping("/{postId}")  
public ResponseEntity<PostDto> getPost(@PathVariable long postId) {  
return ResponseEntity.ok(postService.getPost(postId));  
}

Service

@Cacheable(value = "post", key = "#postId")  
public PostDto getPost(long postId) {  
    log.info("Get id: {}", postId);  
    Post post = postRepository.findById(postId)  
        .orElseThrow(EntityNotFoundException::new);  

return modelMapper.map(post, PostDto.class);  
}

Entity

@Entity  
@Data  
public class Post {  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  

    @Column(nullable = false)  
    private String title;  

    @Column  
    private long views = 0;  
}

실행 결과

select * from post

<< H2DB 에는 아무것도 들어있지 않으나

GET http://localhost:8080/1

<< 이전 앱 실행에서 저장된 캐싱 데이터가 튀어나온다.

 

분명히 현재 H2DB에는 데이터가 존재하지 않지만 1번 포스트에 대한 GET 요청을 할 시 데이터를 반환받는다. 해당 데이터는 이전 APP 실행에서 POST 요청을 통해 삽입된 데이터이다.

Solution

관련 문서를 찾아보던 중 해당 문서를 발견했다.
https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/boot-features-caching.html#boot-features-caching-provider-redis

 

Spring Cache는 추상화된 인터페이스로, 실제 캐시가 저장된 공간을 정의하지 않는다. 이는 CacheManager 또는 CacheResolver 에 의해 구체적으로 정의되며 해당 Bean 이 존재하지 않을 경우 해당 순서대로 캐시가 저장될 공간을 탐색한다.

1. Generic
2. JCache
3. EnCache 2.x
4. Hazelcast
5. Infinispan
6. Couchbase
7. Redis
8. Caffeine
9. Simple (In-memory)

여기서 9번 Simple 이 바로 Spring Application 의 In-memory 캐싱을 의미한다.

 

나의 경우는 현재 프로젝트 내에서 Redis 설정 Bean 과 Redis docker container 가 설정되어 있었기 때문에 7번 Redis 가 감지되었고 9번 In-memory 보다 우선순위가 높기 때문에 Caching 공간으로 채택된 것이다.

 

외부 저장공간을 캐싱 공간으로 사용하였기 때문에 당연히 Spring Application 을 재시작 해도 캐싱된 데이터가 남아있었던 것이다.

확인해 보니 정말로 캐싱된 데이터가 Redis에 들어있었다...

 

Redis 를 사용하는 동시에 Spring Cache 는 In-memory 를 사용하고 싶다면 application.yml 에 해당 설정을 추가해 주면 된다. 해당 설정을 통해 Spring Cache 저장공간을 디텍팅 하는 방식에서 강제로 고정시킬 수 있다. 만약 설정한 저장 공간이 설정되어 있지 않는다면 Spring 시작 시 예외가 발생한다.

spring:
  cache:
    type: simple

 

Reference