Google 태그 관리자 아이콘

새로운 로직접근

.findout(RedisTemplate에서 prefix key만들기)

silvergoni 2020. 12. 20. 00:49
반응형

고민

  • 이미 RedisTemplate를 많이 쓰고 있는 와중에 특정 spring profile에서만 prefix를 붙이는 니즈가 생겼다.
  • cacheManager에서는 prefix를 지원하지만 cacheManager를 사용하고 있는 상황도 아니었고 모든걸 찾아 바꾸기에는 다른작업자분들의 내용이 있어 쉽지 않았다.

결론

  • 정식으로 지원되는 메소드는 찾을 수 없었다.
  • redisTemplate의 keySerializer 메소드로 해결할 수 있엇다.

접근방법

  • RedisConfig에서 RedisTemplate를 정의할때, setKeySerializer를 커스텀하게 만들어준다.

    @Configuration
    public class RedisConfig {
    
      @Autowired
      private PrefixedStringKeySerializer prefixedStringKeySerializer;
    
      @Bean
      public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
          RedisTemplate<String, Object> redisTemplate = new RedisTemplate();
          ... 중략 ...
          redisTemplate.setKeySerializer(prefixedStringKeySerializer);
          return redisTemplate;
      }
  • PrefixedStringKeySerializer는 StringRedisSerializer를 상속한다.

  • env에서 active profile을 파악하고 타겟한 profile(코드 중 TARGET_ACTIVE_PROFILE)이 있을때는 prefix(코드 중 KEY_PREFIX)를 key에 더해서 serialize가 진행되도록 넘겨준다.

    @Component
    public class PrefixedStringKeySerializer extends StringRedisSerializer {
      private static final Logger log = LoggerFactory.getLogger(PrefixedStringKeySerializer.class);
    
      @Autowired
      private Environment env;
    
      @Override
      public byte[] serialize(@Nullable String string) {
          try {
               Optional<String> opStageProfile = Stream.of(env.getActiveProfiles())
                  .filter(profile -> StringUtils.equals(profile, TARGET_ACTIVE_PROFILE))
                  .findAny();
    
              if (opStageProfile.isPresent()) {
                  return super.serialize(KEY_PREFIX + string);
              }
          } catch (Exception e) {
              log.error("[PREFIXED_STRING_KEY_SERIALIZER] failed to find active profile", e);
          }
    
          return super.serialize(string);
      }
    }
  • spring-data-redis에 관련된 내용만 테스트하니 @DataRedisTest를 사용해준다.

  • TARGET_ACTIVE_PROFILE에서만 실행되도록 @ActiveProfiles를 이용해준다.

  • 위의 설정으로 테스트할 수 있게 IMPORT

    @RunWith(SpringRunner.class)
    @DataRedisTest
    @Import({RedisConfig.class, PrefixedStringKeySerializer.class})
    @ActiveProfiles(TARGET_ACTIVE_PROFILE)
    public class RedisConfigStageTest {
      private final String redisKey= "stagePrefixTestKey" + LocalDateTime.now().toLocalTime();
    
      @Autowired
      private RedisTemplate redisTemplate;
    
      @Test
      public void stage_prefix적용_테스트() {
          //when
          redisTemplate.opsForValue().set(redisKey, "1");
          String result = String.valueOf(redisTemplate.opsForValue().get(redisKey));
          Set<String> stageNamedKeySet = redisTemplate.keys(redisKey);
          String storedKeyName = stageNamedKeySet.stream().findFirst().orElseThrow(() -> new RuntimeException());
    
          //then
          assertThat(result).isEqualTo("1");
          assertThat(storedKeyName).isEqualTo(KEY_PREFIX + redisKey);
      }
    
      @After
      public void teardown() {
          redisTemplate.delete(redisKey);
      }
    }
  • 테스트 작성중 재밌었던 부분은 확인하는 과정이다. 모든 키가 자동으로 prefix가 붙어서 실제로 잘 들어갔는지 테스트가 난감했었는데 redisTemplate.keys(-) 메소드를 통해서 실제 등록된 키를 가져와서 비교해볼 수 있었다.