Spring Boot 2 에서 Spring Boot 3 으로 마이그레이션 하면서 Redis 역/직렬화 이슈가 발생하였습니다.
아래 문서를 읽고 기존에 사용하던 Jackson2JsonRedisSerializer 라이브러리를 GenericJackson2JsonRedisSerializer 라이브러리로 교체하였습니다.
https://docs.spring.io/spring-session/reference/configuration/redis.html
GenericJackson2JsonRedisSerializer
GenericJackson2JsonRedisSerializer 클래스는 Spring Data Redis에서 제공하는 RedisSerializer의 구현체 중 하나로, Java 객체를 JSON으로 직렬화하거나 JSON을 Java 객체로 역직렬화하는 데 사용됩니다. 이 직렬화기는 Jackson 라이브러리를 기반으로 합니다.
GenericJackson2JsonRedisSerializer의 특징
유연성
이 직렬화기는 ObjectMapper를 사용하여 객체를 JSON으로, JSON을 객체로 변환합니다.
사용자가 직렬화 과정에서 사용할 ObjectMapper를 커스터마이즈 할 수 있어 다양한 설정을 적용할 수 있는 유연성을 제공합니다.
타입 정보 저장
기본 설정에서, GenericJackson2JsonRedisSerializer는 객체의 클래스 타입 정보를 JSON에 저장합니다. 이는 역직렬화 시 정확한 타입으로 객체를 복원할 수 있도록 도와주지만, JSON의 크기를 증가시킬 수 있습니다. 필요에 따라 이 기능을 비활성화할 수도 있습니다.
보안 설정
기본적으로 이 직렬화기는 타입 정보를 사용하여 역직렬화를 수행할 때 특정 클래스 타입으로의 역직렬화를 제한하여 보안 위험을 감소시킵니다. 예를 들어, 알려지지 않은 타입으로의 역직렬화 시도를 차단할 수 있습니다.
GenericJackson2JsonRedisSerializer를 사용하는 예는 다음과 같습니다. Spring에서 RedisTemplate 설정 시 이 직렬화기를 사용할 수 있습니다.
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
template.setValueSerializer(serializer);
template.setHashValueSerializer(serializer);
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
이 설정은 모든 Redis 값에 대해 JSON 형태로 직렬화를 수행하도록 설정합니다.
키에 대해서는 StringRedisSerializer를 사용하여 문자열로 직렬화합니다.
GenericJackson2JsonRedisSerializer 주의 사항
성능과 저장 공간
JSON 직렬화는 바이너리 직렬화에 비해 CPU 자원을 더 많이 사용하며, 저장 공간도 더 많이 필요할 수 있습니다. 직렬화된
데이터의 크기가 중요한 경우 다른 직렬화 방법을 고려할 수 있습니다.
역직렬화 문제
클래스 타입 정보가 변경되거나 삭제되었을 때 역직렬화 과정에서 오류가 발생할 수 있습니다. 이는 클래스 정의가 변경된 경우에 특히 문제가 될 수 있습니다.
GenericJackson2JsonRedisSerializer는 매우 유용하지만, 사용 사례에 따라 적절한 설정과 관리가 필요합니다.
GenericJackson2JsonRedisSerializer 을 활용하여 직렬화와 역직렬화하는 방법
public void saveDataToRedis(String key, SomeObject data) {
redisTemplate.opsForValue().set(key, data);
}
public SomeObject fetchDataFromRedis(String key) {
return (SomeObject) redisTemplate.opsForValue().get(key);
}
GenericJackson2JsonRedisSerializer 고급 설정 및 사용자 정의
GenericJackson2JsonRedisSerializer는 내부적으로 ObjectMapper를 사용합니다. 기본 생성자 외에도 사용자 정의 ObjectMapper를 인자로 받는 생성자를 제공하여, 직렬화 및 역직렬화 동작을 더 세밀하게 제어할 수 있습니다.
사용자 정의 ObjectMapper 설정 예제
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// ObjectMapper 사용자 정의
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); // 타입 정보 포함 설정
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); // 날짜와 시간 형식 설정
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(objectMapper);
template.setValueSerializer(serializer);
template.setHashValueSerializer(serializer);
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
참고문서
'개발중 > Spring Boot & Redis' 카테고리의 다른 글
Spring Boot와 Redis를 사용한 데이터 저장 및 관리 (0) | 2024.05.03 |
---|---|
Spring Boot 2.x.x에서 3.x.x로 업그레이드 후 Redis에 Java 객체 저장 문제 발생 (0) | 2024.04.16 |
클래스 변경과 직렬화: Spring Redis 환경에서의 serialVersionUID 관리 (0) | 2023.11.17 |
로컬에서는 Spring Session, 배포에서는 Redis: 세션 저장소 분리 전략 (0) | 2023.09.20 |
Spring Security에서 Redis를 사용하면서 겪은 SessionRegistry 문제 (0) | 2023.09.20 |