티스토리 뷰

 

[Redis] HATEOAS와 @Cacheable

이전 Redis 삽질기에서 해결법은 찾지 못 했으나 타협점을 찾았기 때문에 올린다 내가 의도 했던 것은 RestController 응답을 HATEOAS에 맞춰 ResponseEntity 또는 ResponseEntity 로 내려주려고 했다 또한 응답.

ryumodrn.tistory.com

 

위 글에서 이어지는 글이다

많은 우여곡절 끝에 HATEOAS를 적용한 PagedModel 형태에 캐시 추상화 @Cacheable을 접목했다

정확하게 말해 Page를 캐시하고 Controller 단에서 Page 형태의 캐시 데이터를 PagedModel로 변환하여 반환한다

지난 글에서의 문제점은 _links 가 깨진다는 점이었다

 

 

 

사실 위 문제를 해결하고도 PagedModel에 캐시를 적용하는 과정에서 수많은 시간을 쓰고도 실패했다

class java.util.LinkedHashMap cannot be cast to class org.springframework.data.domain.Page

에러 로그를 만나면서 가슴 아픈 시간을 보냈다

java.lang.ClassCastException: class java.util.LinkedHashMap 
cannot be cast to class org.springframework.data.domain.Page 
(java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; 
  org.springframework.data.domain.Page is in unnamed module of loader 'app')
	at com.woomoolmarket.service.member.MemberService$$EnhancerBySpringCGLIB$$7b31efb5.findAllMembers(<generated>)

 

LinkedHashMap은 애플리케이션이 띄워지면서 bootstrap loader에 의해 앱에 올라가는 놈이고

Page는 app loader에 의해 올라가는 놈이라 변환할 수 없다는 것이다

문제 파악하는 데에도 시간이 꽤 걸렸고 문제 해결은 덮어놓고 나중에 생각해야지 하다가 한 달 정도 걸린 것 같다

class java.util.LinkedHashMap cannot be cast to [Custom Object]는 생각보다 자주 만날 수 있는 에러인데

Redis에 저장된 데이터를 꺼내올 때 타입이 지정되지 않으면 LinkedHashMap으로 읽어오면서 발생하는 문제다

즉 레디스에서 반환될 때의 데이터 타입을 추정할 수 없어 터지는 것이다

 

간단한 해결 방법으로 objectMapper.readValue([Custom Object], new TypeReference<어쩌구>)으로 풀면 되지만

조금 깊게 보면 캐시란 것은 핵심 비지니스와 관련이 없다 엄격한 잣대로 로직에 캐시 관련 로직이 침투해서는 안 된다

자바 코드로 해결하지 않고 캐시 추상화를 사용하기 위해 아등바등했다

 

그럼 이 문제를 풀 때 그다음으로 쉽게 푸는 방법이 무엇이 있을까?

난 이전에 CacheManager에 ValueSerializer에 GenericJackson2JsonRedisSerializer를 지정해줬다

얘가 레디스에서 데이터 꺼내올 때 타입을 자꾸 못 찾았으니 다른 Serializer를 사용하면 된다

기본 Serializer인 JdkSerializationRedisSerializer를 넣어주면 byte 형태로 저장된다

내가 설정하고 최근까지 사용 중인 CacheManger는 아래와 같다

    @Primary
    @Bean(name = "jdkCacheManager")
    public RedisCacheManager jdkCacheManager() {
        RedisCacheConfiguration configuration = RedisCacheConfiguration
            .defaultCacheConfig()
            .disableCachingNullValues()
            .entryTtl(Duration.ofDays(1))
            .serializeKeysWith(SerializationPair.fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()));

        return RedisCacheManagerBuilder
            .fromConnectionFactory(redisConnectionFactory)
            .cacheDefaults(configuration)
            .build();
    }

 

위 CacheManager를 이용해 데이터를 반환받아보면 아래와 같이 이쁘게 나온다

 

 

 

이걸로 해결된 걸까?

JdkSerializationRedisSerializer로는 반만 해결됐다

어쨌거나 저장, 반환에는 문제없지만 Redis에 저장된 데이터를 볼 때가 문제다

난 Redis GUI 툴로 Medis를 사용 중인데 JdkSerializationRedisSerializer를 사용해 저장된 데이터는

Hex 형태로 보이고 Viewer type을 JSON이나 plain으로 바꾸면 데이터가 보이지 않는다

 

 

레디스에 저장된 데이터 관리가 필요하다면 사용할 수 없는 방법이겠다

다른 방법으로도 풀어보려고 여러 시도를 했다

ObjectMapper에 타입을 알려줘야 하므로 HATEOAS와 관련된 HalModule 등을 넣어주고 이놈을 주입받아서

GenericJackson2JsonRedisSerializer()의 인자로 넣어서 해보기도 했는데 ClassCastException의 벽을 넘을 수 없었다

일단은 HATEOAS + @Cacheable 적용은 해결했으니 한 타임 쉬어가기로 하고 추후 더 개선해봐야겠다

 

 

자료를 조금 더 찾아본 결과로는

1. PagedModel을 직접 Serialize, Deserialize 하는 모듈을 만들어서 ObjectMapper에 넣어주는 방법이 있고

2. PagedModel을 상속받고 상속받은 놈에 implements Serializable을 하는 방법이 있을 것 같은데

둘 다 만만한 작업이 될 것 같진 않아 후일을 기약해야겠다

 

 

만약 이에 대해 좋은 방법을 알고 계시는 분이 있다면 알려주시면 참 감사하겠습니다 😭

 

 


 

개선본

 

[Redis] HATEOAS와 @Cacheable - 3

[Redis] HATEOAS와 @Cacheable - 2 [Redis] HATEOAS와 @Cacheable 이전 Redis 삽질기에서 해결법은 찾지 못 했으나 타협점을 찾았기 때문에 올린다 내가 의도 했던 것은 RestController 응답을 HATEOAS에 맞춰 Re..

ryumodrn.tistory.com

 

댓글
링크
글 보관함
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Total
Today
Yesterday