관리 메뉴

HeBhy, since 1983.

Spring Redis Cache Configuration class(deserialize시 no class def error 방지, 캐시별 시간 차등, serialized JSON value로 저장하는 cacheManager 추가) 본문

Dev/Web

Spring Redis Cache Configuration class(deserialize시 no class def error 방지, 캐시별 시간 차등, serialized JSON value로 저장하는 cacheManager 추가)

HeBhy 2020. 5. 29. 22:12

Redis 클러스터를 통해 메모리만 충분하다면.. 그리고 자주 갱신되지 않는 데이터라면 엄청난 속도 향상을 가져다 주는 캐시이니 꼭 사용합시다..

 

1. 스프링 부트의 설정파일을 사용하지 않습니다. (커스텀 작업이 필요하므로)

 

2. 역직렬화시, 에러뿜뿜을 방지해줍니다.

  -devtools 안꺼도 됩니다. 에러가 나는 가장 빈번한 이유는 detach되지 않은(persistant bag)을 가진 entity를 그대로 저장했기 때문이니.. @Cacheable이나 @CachePut시에 cacheManager="gsonCacheManager"로 변경해주면 됩니다..

 

3. 캐시별 시간 차등이(cacheName을 통해) 가능합니다.

 

4. Json 캐시매니저를 사용해서, 일반 객체로 저장(로딩)시 에러가 나는것들은 json 캐시매니저를 통해 저장합니다. (entity에 toString()시 objectMapper을 이용해 json으로 출력하는 @Override함수를 추가한경우 왠만하면 에러가 나지 않습니다..)

 

캐시 기본사용법은 아래 주석을 참고해주세요..!

 

package com.example.config;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.redis.cache.CacheKeyPrefix;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheManager.RedisCacheManagerBuilder;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/*
* 기본으로 redis에 cacheName::key 형태로 구분되어 저장됨. key를 생략할 경우, "SimpleKey []" 로 저장됨.
1. @Cacheable: 읽을때. 
  -예시: @Cacheput 참고.
2. @CachePut: 갱신
  -예시: @Cacheable(value="photo", key="#file.fileID", condition="#file.fileName='test'", unless="#result == null", cacheManager="gsonCacheManager")
3. @CacheEvict: 삭제(cacheManager 지정하면 안됨!)
  -예시: @CacheEvict(value="photo", key="#file.fileID")
4. @Caching: 한 메소드에 여러 어노테이션이 필요할때 그룹화 해줌.
  -예시: @Caching( evict= { @CacheEvict(...), @CacheEvict(...) }, ... )
5. 어노테이션 외에 직접 캐시매니저를 통해 캐시 접근이 필요한 경우
  -서비스 class에서 @Autowired private CacheManager cacheManager; 선언
  -함수 안에서 cacheManager.getCache("cacheName").evict("key") 처럼 처리하면 됨.
*/
@Configuration
@EnableCaching
public class RedisCacheConfig {
  
  //************************
  // 일반 객체용 캐시매니저
  //************************
  @Primary
  @Bean(name = "cacheManager")
  public RedisCacheManager cacheManager(RedisConnectionFactory cf, ResourceLoader rl) {   // 기본 캐시매니저(객체 통째로 보관)

    RedisCacheManagerBuilder builder= RedisCacheManagerBuilder.fromConnectionFactory(cf);
    RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig(rl.getClassLoader())
      .disableCachingNullValues()       // 널값 금지(캐싱시 unless("#result == null") 필수.)
      .entryTtl(Duration.ofDays(1))     // 기본 캐시 1일 유지.
      .computePrefixWith(CacheKeyPrefix.simple())       // name::key 처럼 key앞에 '::'를 삽입(redis-cli에서 get "name::key" 로 조회.)
      .serializeKeysWith(SerializationPair.fromSerializer(new StringRedisSerializer()));
      
    // 캐시별로 유효시간 다르게 정하기.
    Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();    

    // 3초
    Duration d3s= Duration.ofSeconds(3);
    cacheConfigurations.put("pageHot100Talk", configuration.entryTtl(d3s));

    // 10분
    Duration d10m= Duration.ofMinutes(10);
    cacheConfigurations.put("listKeyword", configuration.entryTtl(d10m));

    // 1시간
    Duration d1h= Duration.ofHours(1);
    cacheConfigurations.put("listExMain", configuration.entryTtl(d1h));
        
    return builder.cacheDefaults(configuration).withInitialCacheConfigurations(cacheConfigurations).build();
  }



  //************************
  // generic json용 캐시매니저
  //************************
  @Bean(name = "gsonCacheManager") 
  public RedisCacheManager gsonCacheManager(RedisConnectionFactory cf, ResourceLoader rl) {  // json으로 값 보관(detache가 필요한 entity들- 회원정보, ... 등)

    RedisCacheManagerBuilder builder= RedisCacheManagerBuilder.fromConnectionFactory(cf);
    RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig(rl.getClassLoader())
      .disableCachingNullValues()
      .entryTtl(Duration.ofDays(1))     // 기본 캐시 1일 유지.
      .computePrefixWith(CacheKeyPrefix.simple())
      .serializeKeysWith(SerializationPair.fromSerializer(new StringRedisSerializer()))
      .serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));     //  json형식으로 value 저장.
      
    // 캐시별로 유효시간 다르게 정하기.
    Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();

    // 1시간
    Duration d1h= Duration.ofHours(1);
    cacheConfigurations.put("listCategory", configuration.entryTtl(d1h));

    return builder.cacheDefaults(configuration).withInitialCacheConfigurations(cacheConfigurations).build();
  }


}
Comments