package com.iclass.esb.engine.cache.redis;
import com.iclass.esb.engine.cache.ESBCache;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.SerializationUtils;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
/**
* Created by xxxx on 2015/9/11.
*/
public class RedisCache implements ESBCache {
private ShardedJedisPool jedisPool;
public static final long DEFAULT_TIMEOUT = 30 * 60 * 1000;
private static final int DEFAULT_WAIT_TIME = 5;//同步锁的默认等待时间
private final static Logger LOGGER = LoggerFactory.getLogger(RedisCache.class);
private final static int DEFAULT_EXPIRE = 2 * 60 * 60;
@Override
public <T> T get(String key) {
Object result = new Executor<Object>(jedisPool.getResource(), key) {
@Override
Object excute(ShardedJedis jedis, String key) {
byte[] keyBytes = SerializationUtils.serialize(key);
byte[] valueBytes = jedis.get(keyBytes);
return SerializationUtils.deserialize(valueBytes);
}
}.getResult();
return result == null ? null : (T) result;
}
public <T> T getByLock(String key) {
Object result = new Executor<Object>(jedisPool.getResource(), key) {
@Override
Object excute(ShardedJedis jedis, String key) {
lock(key);
LOGGER.info("对{}进行加锁", key);
byte[] keyBytes = SerializationUtils.serialize(key);
byte[] valueBytes = jedis.get(keyBytes);
return SerializationUtils.deserialize(valueBytes);
}
}.getResult();
return result == null ? null : (T) result;
}
@Override
public boolean set(String key, final Object value) {
ShardedJedis jedis = jedisPool.getResource();
byte[] keyBytes = SerializationUtils.serialize(key);
byte[] valueBytes = SerializationUtils.serialize(value);
jedis.set(keyBytes, valueBytes);
jedis.expire(keyBytes, DEFAULT_EXPIRE);
jedisPool.returnResourceObject(jedis);
return true;
}
@Override
public boolean set(String key, Object value, int expire) {
ShardedJedis jedis = jedisPool.getResource();
byte[] keyBytes = SerializationUtils.serialize(key);
byte[] valueBytes = SerializationUtils.serialize(value);
jedis.set(keyBytes, valueBytes);
jedis.expire(keyBytes, expire);
jedisPool.returnResourceObject(jedis);
return true;
}
@Override
public void lock(String key, long timeout) {
long orginalTimeout = timeout;
while (timeout >= 0) {
ShardedJedis shardedJedis = this.getJedisPool().getResource();
long expires = System.currentTimeMillis() + timeout + 1;
String expiresStr = String.valueOf(expires);
if (shardedJedis.setnx(key + "_lock", expiresStr) == 1) {
shardedJedis.expire(key + "_lock", Integer.valueOf("" + timeout));
this.getJedisPool().returnResourceObject(shardedJedis);
return;
}
String currentValueStr = shardedJedis.get(key + "_lock");
if (StringUtils.isEmpty(currentValueStr)) {
this.getJedisPool().returnResourceObject(shardedJedis);
continue;
}
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
LOGGER.info("key:{} 已过锁过期时间将强制获取锁,并重置锁时间。", key);
String oldValueStr = shardedJedis.getSet(key + "_lock", expiresStr);
if (currentValueStr.equals(oldValueStr)) {
expires = System.currentTimeMillis() + orginalTimeout + 1;
expiresStr = String.valueOf(expires);
shardedJedis.set(key + "_lock", expiresStr);
this.getJedisPool().returnResourceObject(shardedJedis);
return;
}
else{
shardedJedis.set(key+"_lock",oldValueStr);
timeout = orginalTimeout;
}
}
timeout -= 10;
try {
this.getJedisPool().returnResourceObject(shardedJedis);
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void lockTransaction(String key, String transactionToken) {
lockTransaction(key, DEFAULT_TIMEOUT, transactionToken);
}
@Override
public void lockTransaction(String key, long timeout, String transactionToken) {
if (StringUtils.isEmpty(transactionToken)){
lock(key,timeout);
return;
}
String lockTransactionToken = get(key + "-lock-transaction-token");
if (StringUtils.isNoneBlank(lockTransactionToken)) {
if (StringUtils.equals(lockTransactionToken, transactionToken)) {
return;
}
}
lock(key, timeout);
while (true) {
try {
lockTransactionToken = get(key + "-lock-transaction-token");
if (StringUtils.isEmpty(lockTransactionToken)) {
set(key + "-lock-transaction-token", transactionToken, DEFAULT_EXPIRE);
return;
}
Thread.sleep(10);
} catch (InterruptedException e) {
LOGGER.error("release transaction lock token error", e);
}
}
}
@Override
public void unlockTransaction(String key) {
unlock(key);
evict(key + "-lock-transaction-token");
}
@Override
public void lock(String key) {
lock(key, DEFAULT_TIMEOUT);
}
@Override
public void unlock(String key) {
ShardedJedis jedis = jedisPool.getResource();
try {
LOGGER.info("key:{}已清除锁成功", key);
jedis.del(key + "_lock");
} finally {
jedisPool.returnResourceObject(jedis);
}
}
@Override
public boolean evict(String key) {
ShardedJedis jedis = jedisPool.getResource();
try {
jedis.del(SerializationUtils.serialize(key));
} finally {
jedisPool.returnResourceObject(jedis);
}
return true;
}
abstract class Executor<T> {
private ShardedJedis jedis = null;
private String key;
public Executor(ShardedJedis jedis, String key) {
this.jedis = jedis;
this.key = key;
}
abstract T excute(ShardedJedis jedis, String key);
public T getResult() {
T result = null;
try {
//1.判断key有没有锁
while (StringUtils.isNoneEmpty(jedis.get(key + "_lock"))) {
Thread.sleep(DEFAULT_WAIT_TIME);
}
//2.没有锁才能继续操作
result = excute(jedis, key);
} catch (Exception e) {
jedisPool.returnResourceObject(jedis);
throw new RuntimeException("Redis命令执行失败", e);
} finally {
jedisPool.returnResourceObject(jedis);
}
return result;
}
}
public ShardedJedisPool getJedisPool() {
return jedisPool;
}
public void setJedisPool(ShardedJedisPool jedisPool) {
this.jedisPool = jedisPool;
}
}
import com.iclass.esb.engine.cache.ESBCache;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.SerializationUtils;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
/**
* Created by xxxx on 2015/9/11.
*/
public class RedisCache implements ESBCache {
private ShardedJedisPool jedisPool;
public static final long DEFAULT_TIMEOUT = 30 * 60 * 1000;
private static final int DEFAULT_WAIT_TIME = 5;//同步锁的默认等待时间
private final static Logger LOGGER = LoggerFactory.getLogger(RedisCache.class);
private final static int DEFAULT_EXPIRE = 2 * 60 * 60;
@Override
public <T> T get(String key) {
Object result = new Executor<Object>(jedisPool.getResource(), key) {
@Override
Object excute(ShardedJedis jedis, String key) {
byte[] keyBytes = SerializationUtils.serialize(key);
byte[] valueBytes = jedis.get(keyBytes);
return SerializationUtils.deserialize(valueBytes);
}
}.getResult();
return result == null ? null : (T) result;
}
public <T> T getByLock(String key) {
Object result = new Executor<Object>(jedisPool.getResource(), key) {
@Override
Object excute(ShardedJedis jedis, String key) {
lock(key);
LOGGER.info("对{}进行加锁", key);
byte[] keyBytes = SerializationUtils.serialize(key);
byte[] valueBytes = jedis.get(keyBytes);
return SerializationUtils.deserialize(valueBytes);
}
}.getResult();
return result == null ? null : (T) result;
}
@Override
public boolean set(String key, final Object value) {
ShardedJedis jedis = jedisPool.getResource();
byte[] keyBytes = SerializationUtils.serialize(key);
byte[] valueBytes = SerializationUtils.serialize(value);
jedis.set(keyBytes, valueBytes);
jedis.expire(keyBytes, DEFAULT_EXPIRE);
jedisPool.returnResourceObject(jedis);
return true;
}
@Override
public boolean set(String key, Object value, int expire) {
ShardedJedis jedis = jedisPool.getResource();
byte[] keyBytes = SerializationUtils.serialize(key);
byte[] valueBytes = SerializationUtils.serialize(value);
jedis.set(keyBytes, valueBytes);
jedis.expire(keyBytes, expire);
jedisPool.returnResourceObject(jedis);
return true;
}
@Override
public void lock(String key, long timeout) {
long orginalTimeout = timeout;
while (timeout >= 0) {
ShardedJedis shardedJedis = this.getJedisPool().getResource();
long expires = System.currentTimeMillis() + timeout + 1;
String expiresStr = String.valueOf(expires);
if (shardedJedis.setnx(key + "_lock", expiresStr) == 1) {
shardedJedis.expire(key + "_lock", Integer.valueOf("" + timeout));
this.getJedisPool().returnResourceObject(shardedJedis);
return;
}
String currentValueStr = shardedJedis.get(key + "_lock");
if (StringUtils.isEmpty(currentValueStr)) {
this.getJedisPool().returnResourceObject(shardedJedis);
continue;
}
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
LOGGER.info("key:{} 已过锁过期时间将强制获取锁,并重置锁时间。", key);
String oldValueStr = shardedJedis.getSet(key + "_lock", expiresStr);
if (currentValueStr.equals(oldValueStr)) {
expires = System.currentTimeMillis() + orginalTimeout + 1;
expiresStr = String.valueOf(expires);
shardedJedis.set(key + "_lock", expiresStr);
this.getJedisPool().returnResourceObject(shardedJedis);
return;
}
else{
shardedJedis.set(key+"_lock",oldValueStr);
timeout = orginalTimeout;
}
}
timeout -= 10;
try {
this.getJedisPool().returnResourceObject(shardedJedis);
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void lockTransaction(String key, String transactionToken) {
lockTransaction(key, DEFAULT_TIMEOUT, transactionToken);
}
@Override
public void lockTransaction(String key, long timeout, String transactionToken) {
if (StringUtils.isEmpty(transactionToken)){
lock(key,timeout);
return;
}
String lockTransactionToken = get(key + "-lock-transaction-token");
if (StringUtils.isNoneBlank(lockTransactionToken)) {
if (StringUtils.equals(lockTransactionToken, transactionToken)) {
return;
}
}
lock(key, timeout);
while (true) {
try {
lockTransactionToken = get(key + "-lock-transaction-token");
if (StringUtils.isEmpty(lockTransactionToken)) {
set(key + "-lock-transaction-token", transactionToken, DEFAULT_EXPIRE);
return;
}
Thread.sleep(10);
} catch (InterruptedException e) {
LOGGER.error("release transaction lock token error", e);
}
}
}
@Override
public void unlockTransaction(String key) {
unlock(key);
evict(key + "-lock-transaction-token");
}
@Override
public void lock(String key) {
lock(key, DEFAULT_TIMEOUT);
}
@Override
public void unlock(String key) {
ShardedJedis jedis = jedisPool.getResource();
try {
LOGGER.info("key:{}已清除锁成功", key);
jedis.del(key + "_lock");
} finally {
jedisPool.returnResourceObject(jedis);
}
}
@Override
public boolean evict(String key) {
ShardedJedis jedis = jedisPool.getResource();
try {
jedis.del(SerializationUtils.serialize(key));
} finally {
jedisPool.returnResourceObject(jedis);
}
return true;
}
abstract class Executor<T> {
private ShardedJedis jedis = null;
private String key;
public Executor(ShardedJedis jedis, String key) {
this.jedis = jedis;
this.key = key;
}
abstract T excute(ShardedJedis jedis, String key);
public T getResult() {
T result = null;
try {
//1.判断key有没有锁
while (StringUtils.isNoneEmpty(jedis.get(key + "_lock"))) {
Thread.sleep(DEFAULT_WAIT_TIME);
}
//2.没有锁才能继续操作
result = excute(jedis, key);
} catch (Exception e) {
jedisPool.returnResourceObject(jedis);
throw new RuntimeException("Redis命令执行失败", e);
} finally {
jedisPool.returnResourceObject(jedis);
}
return result;
}
}
public ShardedJedisPool getJedisPool() {
return jedisPool;
}
public void setJedisPool(ShardedJedisPool jedisPool) {
this.jedisPool = jedisPool;
}
}