spring-data-redis에서 제공해주는 RedisTemplate을 사용하면 @Cacheable 어노테이션을 사용할 수도 있고, Jedis를 이용한 Redis 사용을 쉽게 개발할수 있는 장점이 있습니다.
하지만 현재 spring-data-redis 1.1.0 버전에서 제공해 주는 RedisTemplate은 샤드를 지원해 주지 않고 있기 때문에 시스템 구성이 샤드로 되어 있는 경우 spring-data-redis의 RedisTemplate을 사용할 수가 없습니다.
그래서 샤드를 지원하는 레디스 템플릿을 만들어 보기 위해 구글링을 하던 중 중국 개발자가 만들어 놓은 ShardedJedisTemplate를 찾을수 있었고, 약간의 수정을 하여 Template 클래스를 만들었습니다.
1. RedisException
package net.krespo.redis.exception;
public class RedisException extends RuntimeException{
private static final long serialVersionUID = 9150947297211556907L;
public RedisException() {
super();
}
public RedisException(String message, Throwable cause) {
super(message, cause);
}
public RedisException(String message) {
super(message);
}
public RedisException(Throwable cause) {
super(cause);
}
}
2. ShardedJedisPoolUtils
package net.krespo.redis.jedis.util;
import net.krespo.redis.jedis.ShardedJedisCallback;
import net.krespo.redis.jedis.ShardedJedisReturnedCallback;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
import redis.clients.jedis.exceptions.JedisConnectionException;
/**
* 레디스의 실행 및 실행결과를 리턴해주는 유틸
* **/
public class ShardedJedisPoolUtils {
/**
* 리턴값이 필요한 Command 실행
* */
public static T execute(ShardedJedisPool jedisPool, ShardedJedisReturnedCallback shardedJedisReturnedCallback) {
ShardedJedis shardedJedis = null;
try {
shardedJedis = jedisPool.getResource();
T returnValue = shardedJedisReturnedCallback.doInShardedJedis(shardedJedis);
return returnValue;
}
//장애로 인해 레디스 커넥션이 맺어지지 않으면 커넥션풀에서 해당 커넥션을 제거한다.
catch (JedisConnectionException e) {
if(shardedJedis != null) jedisPool.returnBrokenResource(shardedJedis);
return null;
}
finally{
if (shardedJedis != null) {
jedisPool.returnResource(shardedJedis);
}
}
}
/**
* 리턴값이 필요 없는 Command 실행
* */
public static void execute(ShardedJedisPool jedisPool, ShardedJedisCallback shardedJedisCallback) {
ShardedJedis shardedJedis = null;
try {
shardedJedis = jedisPool.getResource();
shardedJedisCallback.doInShardedJedis(shardedJedis);
}
//장애로 인해 레디스 커넥션이 맺어지지 않으면 커넥션풀에서 해당 커넥션을 제거한다.
catch (JedisConnectionException e) {
if(shardedJedis != null) jedisPool.returnBrokenResource(shardedJedis);
}
finally{
if (shardedJedis != null) {
jedisPool.returnResource(shardedJedis);
}
}
}
}
3. ShardedJedisCallback
package net.krespo.redis.jedis;
import redis.clients.jedis.ShardedJedis;
public interface ShardedJedisCallback {
void doInShardedJedis(ShardedJedis shardedJedis);
}
4. ShardedJedisReturnedCallback
package net.krespo.redis.jedis;
import redis.clients.jedis.ShardedJedis;
public interface ShardedJedisReturnedCallback {
T doInShardedJedis(ShardedJedis shardedJedis);
}
5. AbstractRedisTemplate
package net.krespo.redis.template;
import net.krespo.redis.exception.RedisException;
public abstract class AbstractRedisTemplate {
protected void handleException(RedisException e) throws RedisException {
throw e;
}
protected RedisException wrapperException(Exception e) {
return new RedisException(e.getMessage(), e);
}
}
6. ShardedJedisTemplate
package net.krespo.redis.jedis;
import net.krespo.redis.exception.RedisException;
import net.krespo.redis.jedis.util.ShardedJedisPoolUtils;
import net.krespo.redis.template.AbstractRedisTemplate;
import redis.clients.jedis.ShardedJedisPool;
public class ShardedJedisTemplate extends AbstractRedisTemplate{
protected ShardedJedisPool shardedJedisPool;
public void setShardedJedisPool(ShardedJedisPool shardedJedisPool) {
this.shardedJedisPool = shardedJedisPool;
}
public T execute(ShardedJedisReturnedCallback shardedJedisReturnedCallback) throws RedisException {
try {
return ShardedJedisPoolUtils.execute(shardedJedisPool, shardedJedisReturnedCallback);
} catch (Exception e) {
handleException(wrapperException(e));
return null;
}
}
public void execute(ShardedJedisCallback shardedJedisCallback) throws RedisException {
try {
ShardedJedisPoolUtils.execute(shardedJedisPool, shardedJedisCallback);
} catch (Exception e) {
handleException(wrapperException(e));
}
}
}
사용법은 아래와 같이 사용하면 됩니다.
package net.krespo.redis.template.jedis;
import java.util.ArrayList;
import java.util.List;
import net.krespo.redis.jedis.ShardedJedisCallback;
import net.krespo.redis.jedis.ShardedJedisReturnedCallback;
import net.krespo.redis.jedis.ShardedJedisTemplate;
import org.junit.Assert;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
public class ShardedJedisTemplateTests {
private JedisPoolConfig config;
private List jedisShardInfos;
private ShardedJedisPool pool;
private ShardedJedisTemplate template;
@Before
public void init() {
config = new JedisPoolConfig();
jedisShardInfos = new ArrayList();
JedisShardInfo shard1 = new JedisShardInfo("호스트1", 포트);
JedisShardInfo shard2 = new JedisShardInfo("호스트2", 포트);
shard1.setPassword("비밀번호");
shard2.setPassword("비밀번호");
jedisShardInfos.add(shard1);
jedisShardInfos.add(shard2);
pool = new ShardedJedisPool(config, jedisShardInfos);
template = new ShardedJedisTemplate();
template.setShardedJedisPool(pool);
}
@Test
public void shardedJedisTemplateCallbackTest() {
template.execute(new ShardedJedisCallback() {
public void doInShardedJedis(ShardedJedis shardedJedis) {
String status = shardedJedis.set("test:key", "testvalue");
Assert.assertEquals("OK", status);
}
});
}
@Test
public void shardedJedisTemplateReturnedCallbackTest() {
String value = template.execute(new ShardedJedisReturnedCallback() {
public String doInShardedJedis(ShardedJedis shardedJedis) {
return shardedJedis.get("test:key");
}
});
Assert.assertNotNull(value);
Assert.assertEquals("testvalue", value);
}
}