본문 바로가기

Programming/개인 프로젝트

[중고거래장터 - Study&Refactoring] 캐싱 기능 적용(Spring MVC + Redis + Jedis) Java 클래스 방식

반응형

Redis를 통한 캐싱 기능 설정은 XML 파일 작성 또는 Java 클래스 설정 두 가지 방식이 있습니다. 지난 글에서는 XML 파일 작성 방식을 소개했기 때문에 이번에는 Java 클래스 방식으로 Redis 캐싱 기능 설정 방식을 소개하겠습니다.

지난 글에 소개한 XML 방식과 마찬가지로 Redis + Jedis 방식으로 구현했습니다.

 

개발환경

  • Spring Legacy Project(MVC)
  • Spring 5.0.7
  • Maven
  • Java 1.8
  • MySQL 8.0.27
  • Redis-x64-3.2.100

 

redis 사용을 위한 의존성 설정을 pom.xml 파일에 합니다.

 

pom.xml

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.1</version>
</dependency>

 

Java 설정 클래스 입니다. 이 클래스 하나만 등록하면 끝입니다.

 

RedisConfig.java

import java.lang.reflect.Method;
import java.time.Duration;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import lombok.extern.log4j.Log4j;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
@EnableCaching
@Log4j
public class RedisConfig extends CachingConfigurerSupport {
	
	/*
	 * 캐시 설정
	 */

	/**
	 * redis 2.0 버전 이후부터 RedisStandaloneConfiguration 클래스로 설정해야 합니다.
	 */
	@Bean
	public RedisConnectionFactory redisConnectionFactory() {
		RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
		redisStandaloneConfiguration.setHostName("127.0.0.1");
		redisStandaloneConfiguration.setPort(6379);
		JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpccb = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) 
				JedisClientConfiguration.builder();
		jpccb.poolConfig(jedisPoolConfig());
		JedisClientConfiguration jedisClientConfiguration = jpccb.build();
		return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
	}

	private JedisPoolConfig jedisPoolConfig() {
		final JedisPoolConfig poolConfig = new JedisPoolConfig();
		poolConfig.setMaxIdle(300);
		poolConfig.setMaxTotal(2000);
		poolConfig.setMaxWaitMillis(1000);
		poolConfig.setTestOnBorrow(true);
		return poolConfig;
	}

	/**
	 * 스프링에서 제공하는 Serializer를 CacheManager에 등록.
	 * 이렇게 하면 캐싱되는 모델마다 Serializable을 implements할 필요가 없다.
	 */
	@Bean
	public CacheManager cacheManager(final RedisConnectionFactory factory) {
		Duration expiration = Duration.ofSeconds(300);
		RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .entryTtl(expiration);
		
		return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(factory).cacheDefaults(redisCacheConfiguration).build();
	}

	@Bean
	public RedisTemplate<String, Object> redisTemplate() {
		final RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
		template.setConnectionFactory(redisConnectionFactory());
		template.setKeySerializer(new StringRedisSerializer());
		template.setHashKeySerializer(new GenericToStringSerializer<Object>(Object.class));
		template.setValueSerializer(new Jackson2JsonRedisSerializer<>(String.class));
		return template;
	}
	
	@Bean
	public KeyGenerator keyGenerator() {
		return new KeyGenerator() {

			@Override
			public Object generate(Object o, Method method, Object... objects) {
				StringBuilder sb = new StringBuilder();
				sb.append(o.getClass().getName());
				sb.append(method.getName());
				for (Object obj : objects) {
					sb.append(obj.toString());
				}
				log.debug("KeyGenerator: " + sb);
				return sb.toString();
			}

		};
	}
	
}

 

RedisConnectionFactory

사용자가 입력한 Redis 접속 관련 설정 정보를 담는 객체입니다.

 

JedisPoolConfig

Jedis는 thread-safe하지 않습니다. 따라서 JedisPool 설정을 통해 멀티스레드 환경에서 Jedis 커넥션을 재활용 할 수 있도록 설정해야 합니다. 

 

CacheManager

Redis 캐시 동작 방식(캐시 관리 방식)을 커스터마이징 합니다. 설정을 위해 RedisCacheConfiguration 클래스를 활용합니다.

별다른 수정 내용이 없다면 defaultCacheConfig() 메소드를 사용하면 기본 설정대로 캐싱 작업을 합니다.

 

default 설정(defaultCacheConfig)

  • key expiration : eternal
  • cache null values : yes
  • prefix cache keys : yes
  • default prefix : [the actual cache name]
  • key serializer StringRedisSerializer
  • value serializer : JdkSerializationRedisSerializer

캐시 동작 설정 과정에서 필요한 serializer를 등록할 수 있습니다.

 

Serialization이란 메모리에 객체를 저장하기 위해 전송 객체를 바이트 스트림 형태로 저장하는 것입니다. 이 작업의 이유는, 나중에 다시 호출될 수도 있는 객체의 상태를 저장하기 위해서입니다. Serialization과 반대로 동작하는 것이 Deserialization 입니다. 이 개념은 Redis에 국한되지 않고 프로그래밍 분야에서 통용되는 개념입니다.

반응형