Redis Sentinel模式集成到Spring
Author QiuRiMangCao 秋日芒草
引入jedis依赖jar
jedis-2.9.0.jar
bean 定义,spring为将这个bean包装成一个bean definition, destroy-method=”destroy” 就是对应redis.clients.jedis.JedisSentinelPool中的销毁方法
<bean id="jedisSentinelPool" class="redis.clients.jedis.JedisSentinelPool" destroy-method="destroy">
// 对应redis.clients.jedis.JedisSentinelPool这个类中的构造器参数masterName的设置
<constructor-arg name="masterName">
// 读取资源文件的配置key=redis.sentinel.master.name
<value>${redis.sentinel.master.name}</value>
</constructor-arg>
<constructor-arg name="sentinels">
<set value-type="java.lang.String">
<value>${redis.cluster.host1}</value>
<value>${redis.cluster.host2}</value>
</set>
</constructor-arg>
<constructor-arg name="password">
<value>${redis.auth.password}</value>
</constructor-arg>
// ref="jedisPoolConfig" 引用另一个bean definition,这也是spring自动完成依赖注入的
<constructor-arg name="poolConfig" ref="jedisPoolConfig" />
</bean>
对应properties 文件的配置信息如下
## Redis Cluster
redis.cluster.host1=127.0.0.1:26379
redis.cluster.host2=127.0.0.1:26379
redis.auth.password=
redis.sentinel.master.name=my_master
JedisSentinelPool 中存在JedisSentinelPool 多个构造器方法如下,可以选择不同的构造器进行初始化
public JedisSentinelPool(String masterName, Set<String> sentinels, String password) {
this(masterName, sentinels, new GenericObjectPoolConfig(), Protocol.DEFAULT_TIMEOUT, password);
}
JedisPoolConfig extends GenericObjectPoolConfig,GenericObjectPoolConfig 类中有相关maxTotal的属性定义private int maxTotal = DEFAULT_MAX_TOTAL; 不设置会自动设置一个默认的值
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="minEvictableIdleTimeMillis" value="60000" />
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<property name="numTestsPerEvictionRun" value="-1" />
<property name="maxTotal" value="100" />
<property name="maxIdle" value="50" />
<property name="minIdle" value="10" />
<property name="maxWaitMillis" value="1500"/>
</bean>
redis 工具类的,注入jedisSentinelPool,这样在容器启动后可以直接使用这个工具类来操作相关redis
<bean id="redisUtils" class="com.cn.redis.RedisUtils">
<property name="jedisSentinelPool" ref="jedisSentinelPool" />
</bean>
redisUtils工具类代码
/**
* @描述: Redis缓存工具类.
*/
public class RedisUtils {
private static Logger logger = Logger.getLogger(RedisUtils.class);
/** 默认缓存时间 */
private static final int DEFAULT_CACHE_SECONDS = 60 * 60 * 1;// 单位秒 设置成一个钟
/** 连接池 **/
private static JedisSentinelPool jedisSentinelPool;
/**
* 释放redis资源
*
* @param jedis
*/
private static void releaseResource(Jedis jedis) {
if (jedis != null) {
jedis.close();
// jedisSentinelPool.destroy();
// jedisSentinelPool.returnResource(jedis);
}
}
/**
* 删除Redis中的所有key
*
* @param jedis
* @throws Exception
*/
public static void flushAll() {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
String value = jedis.getSet("agui", "agui") ;
jedis.flushAll();
} catch (Exception e) {
logger.error("Cache清空失败:" , e);
} finally {
releaseResource(jedis);
}
}
/**
* 保存一个对象到Redis中(缓存过期时间:使用此工具类中的默认时间) . <br/>
*
* @param key
* 键 . <br/>
* @param object
* 缓存对象 . <br/>
* @return true or false . <br/>
* @throws Exception
*/
public static Boolean save(Object key, Object object) {
return save(key, object, DEFAULT_CACHE_SECONDS);
}
/**
* 保存一个对象到redis中并指定过期时间
*
* @param key
* 键 . <br/>
* @param object
* 缓存对象 . <br/>
* @param seconds
* 过期时间(单位为秒).<br/>
* @return true or false .
*/
public static Boolean save(Object key, Object object, int seconds) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
jedis.set(SerializeUtils.serialize(key), SerializeUtils.serialize(object));
jedis.expire(SerializeUtils.serialize(key), seconds);
return true;
} catch (Exception e) {
logger.error("Cache保存失败:", e);
return false;
} finally {
releaseResource(jedis);
}
}
/**
* 根据缓存键获取Redis缓存中的值.<br/>
*
* @param key
* 键.<br/>
* @return Object .<br/>
* @throws Exception
*/
public static Object get(Object key) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
byte[] obj = jedis.get(SerializeUtils.serialize(key));
return obj == null ? null : SerializeUtils.unSerialize(obj);
} catch (Exception e) {
logger.error("Cache获取失败:" , e);
return null;
} finally {
releaseResource(jedis);
}
}
/**
* 根据缓存键清除Redis缓存中的值.<br/>
*
* @param key
* @return
* @throws Exception
*/
public static Boolean del(Object key) {
Jedis jedis = null;
try {
// System.out.println(key);
jedis = jedisSentinelPool.getResource();
jedis.del(SerializeUtils.serialize(key));
return true;
} catch (Exception e) {
logger.error("Cache删除失败:" , e);
return false;
} finally {
releaseResource(jedis);
}
}
/**
* 根据缓存键清除Redis缓存中的值.<br/>
*
* @param keys
* @return
* @throws Exception
*/
public static Boolean del(Object... keys) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
jedis.del(SerializeUtils.serialize(keys));
return true;
} catch (Exception e) {
logger.error("Cache删除失败:" , e);
return false;
} finally {
releaseResource(jedis);
}
}
/**
*
* @param key
* @param seconds
* 超时时间(单位为秒)
* @return
*/
public static Boolean expire(Object key, int seconds) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
jedis.expire(SerializeUtils.serialize(key), seconds);
return true;
} catch (Exception e) {
logger.error("Cache设置超时时间失败:" , e);
return false;
} finally {
releaseResource(jedis);
}
}
/**
* 添加一个内容到指定key的hash中
*
* @param key
* @param field
* @param value
* @return
*/
public static Boolean addHash(String key, Object field, Object value) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
jedis.hset(SerializeUtils.serialize(key), SerializeUtils.serialize(field), SerializeUtils.serialize(value));
return true;
} catch (Exception e) {
logger.error("Cache保存失败:" , e);
return false;
} finally {
releaseResource(jedis);
}
}
/**
* 从指定hash中拿一个对象
*
* @param key
* @param field
* @return
*/
public static Object getHash(Object key, Object field) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
byte[] obj = jedis.hget(SerializeUtils.serialize(key), SerializeUtils.serialize(field));
return SerializeUtils.unSerialize(obj);
} catch (Exception e) {
logger.error("Cache读取失败:" , e);
return null;
} finally {
releaseResource(jedis);
}
}
/**
* 从hash中删除指定filed的值
*
* @param key
* @param field
* @return
*/
public static Boolean delHash(Object key, Object field) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
long result = jedis.hdel(SerializeUtils.serialize(key), SerializeUtils.serialize(field));
return result == 1 ? true : false;
} catch (Exception e) {
logger.error("Cache删除失败:" , e);
return null;
} finally {
releaseResource(jedis);
}
}
/**
* 验证该值,在hash中是否存在。
*
* @param key
* @param field
* @return
*/
public static Boolean existsHash(Object key, Object field) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
Boolean result = jedis.hexists(SerializeUtils.serialize(key), SerializeUtils.serialize(field));
return result ;
} catch (Exception e) {
logger.error("Cache验证hash 是否存在该值失败:" , e);
return null;
} finally {
releaseResource(jedis);
}
}
/**
* 拿到缓存中所有符合pattern的key
*
* @param pattern
* @return
*/
public static Set<byte[]> keys(String pattern) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
Set<byte[]> allKey = jedis.keys(("*" + pattern + "*").getBytes());
return allKey;
} catch (Exception e) {
logger.error("Cache获取失败:" , e);
return new HashSet<byte[]>();
} finally {
releaseResource(jedis);
}
}
/**
* 获得hash中的所有key value
*
* @param key
* @return
*/
public static Map<byte[], byte[]> getAllHash(Object key) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
Map<byte[], byte[]> map = jedis.hgetAll(SerializeUtils.serialize(key));
return map;
} catch (Exception e) {
logger.error("Cache获取失败:" , e);
return null;
} finally {
releaseResource(jedis);
}
}
/**
* 判断一个key是否存在
*
* @param key
* @return
*/
public static Boolean exists(Object key) {
Jedis jedis = null;
Boolean result = false;
try {
jedis = jedisSentinelPool.getResource();
result = jedis.exists(SerializeUtils.serialize(key));
return result;
} catch (Exception e) {
logger.error("Cache获取失败:" , e);
return false;
} finally {
releaseResource(jedis);
}
}
/**
* 获取Redis中的key 的 ttl
*
* @param jedis
* @throws Exception
*/
public static long getTtl(String key ) {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
return jedis.ttl(key) ;
} catch (Exception e) {
logger.error("Cache获取ttl失败:" , e);
} finally {
releaseResource(jedis);
}
return 0 ;
}
private static final String LOCK_NODE ="LOCK";
private static ThreadLocal<String> local = new ThreadLocal<>();
/**
* 获取分布式锁
*
* 弊端:只能是redis 单节点好用 所以要保证 该节点不能挂掉
*
*
* @return
*/
public static boolean getLock() {
Jedis jedis = null;
try {
jedis = jedisSentinelPool.getResource();
String value = UUID.randomUUID().toString();
String ret = jedis.set(LOCK_NODE, value, "NX", "PX", 10000);
if(!StringUtils.isEmpty(ret) && ret.equals("OK")){
local.set(value);
return true;
}
} catch (Exception e) {
logger.error("Cache获取锁失败:" , e);
return false;
} finally {
releaseResource(jedis);
}
return false;
}
/**
*
*
* 释放锁
*
*/
public static void releaseLock() {
String script =null;
Jedis jedis = null ;
try {
script = FileCopyUtils.copyToString(new FileReader(ResourceUtils.getFile("classpath:unlock.lua")));
jedis = jedisSentinelPool.getResource();
List<String> keys = new ArrayList<String>();
keys.add(LOCK_NODE);
List<String> args = new ArrayList<String>();
args.add(local.get());
jedis.eval(script, keys, args);
} catch (IOException e) {
logger.error("读取lua 脚本失败 :" + e.getMessage());
} catch (Exception e) {
logger.error("Cache释放锁失败:" , e);
} finally {
releaseResource(jedis);
}
System.out.println(script);
}
public void setJedisSentinelPool(JedisSentinelPool jedisSentinelPool) {
RedisUtils.jedisSentinelPool = jedisSentinelPool;
}
public static JedisSentinelPool getJedisSentinelPool() {
return jedisSentinelPool;
}
}