이번시간엔 redis를 이용한 저장소 캐싱을 해보겠다.
스프링 프로젝트에서 복붙한거라.. 그리고 딱히 어려운부분은 없기에..
일단 레디스를 설치하자.
레디스 윈도우 설치 파일
설치한 후에 레디스를 실행 시키자!

public class RedisCacheManager extends AbstractCacheManager {


    private final RedisConnectionFactory redisConnectionFactory;
    private final RedisTemplate defaultTemplate;
    private final Map<String, RedisTemplate> templates;

    private boolean usePrefix = true;
    private RedisCachePrefix cachePrefix = new DefaultRedisCachePrefix();
    private boolean dynamic = false;

    // 0 - never expire
    private long defaultExpiration = 0;
    private final Map<String, Long> expires;

    public RedisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        this.redisConnectionFactory = redisConnectionFactory;
        this.defaultTemplate = new RedisTemplate();
        this.defaultTemplate.setConnectionFactory(this.redisConnectionFactory);
        this.defaultTemplate.afterPropertiesSet();
        this.templates = new ConcurrentHashMap<>();
        this.expires = new ConcurrentHashMap<>();
    }

    public void setUsePrefix(boolean usePrefix) {
        this.usePrefix = usePrefix;
    }

    public void setCachePrefix(RedisCachePrefix cachePrefix) {
        this.cachePrefix = cachePrefix;
    }

    public void setDynamic(boolean dynamic) {
        this.dynamic = dynamic;
    }

    public void setDefaultExpiration(long defaultExpiration) {
        this.defaultExpiration = defaultExpiration;
    }

    public RedisCacheManager withCache(String cacheName, long expiration) {
        return withCache(cacheName, this.defaultTemplate, expiration);
    }

    public RedisCacheManager withCache(String cacheName, RedisTemplate template, long expiration) {
        this.templates.put(cacheName, template);
        this.expires.put(cacheName, expiration);
        RedisCache cache = createCache(cacheName, template, expiration);
        addCache(cache);
        return this;
    }

    @Override
    public Cache getCache(String name) {
        Cache cache = super.getCache(name);
        if (cache == null && this.dynamic) {
            return createCache(name, this.defaultTemplate, this.defaultExpiration);
        }
        return cache;
    }

    protected RedisCache createCache(String cacheName, RedisTemplate template, long expiration) {
        return new RedisCache(cacheName, (usePrefix ? cachePrefix.prefix(cacheName) : null), template, expiration);
    }

    @Override
    protected Collection<? extends Cache> loadCaches() {
        Assert.notNull(this.defaultTemplate, "A redis template is required in order to interact with data store");
        return this.getCacheNames().stream().map(name -> getCache(name)).collect(Collectors.toList());
    }
}

원래 org.springframework.data.redis.cache에도 RedisCacheManager 가 있기는 한데 불편한듯 싶다.

public class JsonRedisTemplate<V> extends RedisTemplate<String, V> {

    public JsonRedisTemplate(RedisConnectionFactory connectionFactory, ObjectMapper objectMapper, Class valueType) {
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        super.setKeySerializer(stringSerializer);
        super.setHashKeySerializer(stringSerializer);
        super.setHashValueSerializer(stringSerializer);
        Jackson2JsonRedisSerializer jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(valueType);
        jsonRedisSerializer.setObjectMapper(objectMapper);
        super.setValueSerializer(jsonRedisSerializer);
        super.setConnectionFactory(connectionFactory);
        super.afterPropertiesSet();
    }

}

RedisTemplate 도 상속 받아 구현했다.
StringSerializer와 jsonSerializer를 셋팅했다.

@Configuration
@EnableCaching(proxyTargetClass = true)
public class RedisCacheConfig {

    private static final Class CACHE_TYPE = Hello.class;
    private static final String CACHE_NAME = "cache.hello";
    private static final String CACHE_TTL = "${cache.hello.timetolive:60}";
    private static final String NETWORK_CACHE_NAME = "cache.network";

    @Value(CACHE_TTL)
    private Long cacheNetworkTimeToLive;

    @Value(CACHE_TTL)
    private Long cacheBlogTimeToLive;

    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory,
                                          ObjectMapper objectMapper) {

        RedisCacheManager cacheManager = new RedisCacheManager(redisConnectionFactory);

        cacheManager.withCache(NETWORK_CACHE_NAME, this.cacheNetworkTimeToLive);

        JsonRedisTemplate helloTemplate = new JsonRedisTemplate<>(redisConnectionFactory, objectMapper, CACHE_TYPE);
        cacheManager.withCache(CACHE_NAME, helloTemplate, this.cacheBlogTimeToLive);

        return cacheManager;
    }
}

마지막으로 CacheManager 를 빈으로 등록한다.
chche_name은 cache.hello 정하고 캐시 시간은 60초, Type은 Hello로 정했다. Hello 는 일반 자바빈 객체다.
캐시할 목록을 늘려가도 된다.
한번 테스트를 해보자

@Autowired
private CacheManager cacheManager;

@Autowired
private HelloRepository helloRepository;

@Test
public void putRedisCache() {
    Cache cache = cacheManager.getCache("cache.hello");
    cache.put("hello", helloRepository.findOne(1L));
}

@Test
public void getRedisCache() {
    Cache cache = cacheManager.getCache("cache.hello");
    Hello hello = cache.get("hello", Hello.class);
    assertThat(hello.getId(), is(1L));
    assertThat(hello.getName(), is("wonwoo"));
    System.out.println(hello.getName());
}

hello라는 키로 Hello 객체를 한개 넣어 두었다.
그리고 나서 그 다음 테스트는 hello라는 키로 객체를 뽑아 냈다.
성공적으로 테스트가 통과 했다면 캐싱이 된것이다.
테스트가 통과한후 다시 getRedisCache() 메서드를 호출해보자. 그럼 아직도 캐싱되어 있다.
하지만 60초가 지나서 getRedisCache() 테스트만 다시 돌리면 nullpointexception 혹은 테스트를 실패 할 것이다.

이것으로 레디스로 저장소 캐싱을 하는 법을 알아봤다.