Redis集群xml配置和工具类
redis单机改集群
由于公司项目在用为redis单机,在存储和查询性能方面需要调优,所以改为redis集群,自己也研究了一下,配置redisCluster可以通过bean注入也可以写一个工具类,本质都是通过spring容器实例化redisCluster来提供redis数据的存取。下面介绍一下xml配置bean和工具类配置。
bean文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="minIdle" value="${min-idle}" />
<property name="maxIdle" value="${max-idle}" />
<property name="maxTotal" value="${max-active}" />
</bean>
<bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<property name="maxRedirects" value="${maxRedirects}"></property>
<property name="clusterNodes">
<set>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${host1}" />
<constructor-arg name="port" value="${port1}" />
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${host2}" />
<constructor-arg name="port" value="${port2}" />
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${host3}" />
<constructor-arg name="port" value="${port3}" />
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${host4}" />
<constructor-arg name="port" value="${port4}" />
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${host5}" />
<constructor-arg name="port" value="${port5}" />
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${host6}" />
<constructor-arg name="port" value="${port6}" />
</bean>
</set>
</property>
</bean>
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="poolConfig" ref="jedisPoolConfig"></property>
<constructor-arg name="clusterConfig" ref="redisClusterConfiguration" />
<property name="password" value="${password}" />
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="KeySerializer">
<bean
class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
</property>
<property name="ValueSerializer">
<bean
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
</property>
<property name="HashKeySerializer">
<bean
class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
</property>
<property name="HashValueSerializer">
<bean
class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
</property>
</bean>
</beans>
使用的简单的三主三从,通过配置文件注入。
RedisCluster工具类
@Log4j2
@Configuration
@EnableAutoConfiguration
@Component
public class CacheConfig implements Serializable {
private static final long serialVersionUID = -2539468533583469346L;
@Value("${password}")
private String password;
@Value("${timeout}")
private int timeout;
@Value("${namespace}")
private String namespace;
@Value("${maxtotal}")
private int maxtotal;
@Value("${maxidle}")
private int maxidle;
@Value("${minidle}")
private int minidle;
@Value("${maxwaitmillis}")
private int maxwaitmillis;
@Value("${redisClusterNotes}")
private String redisClusterNotes;
@Value("${soTimeout}")
private int soTimeout;
@Value("${maxAttempts}")
private int maxAttempts;
@Value("${maxRedirects}")
private int maxRedirects;
@Bean(name = "jedisPoolConfig")
public JedisPoolConfig getJedisPoolConfig(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxtotal);
jedisPoolConfig.setMaxIdle(maxidle);
jedisPoolConfig.setMinIdle(minidle);
jedisPoolConfig.setMaxWaitMillis(maxwaitmillis);
jedisPoolConfig.setTestOnBorrow(false);
jedisPoolConfig.setTestOnReturn(false);
jedisPoolConfig.setTestWhileIdle(false);
return jedisPoolConfig;
}
@Bean(name = "redisClusterConfiguration")
public RedisClusterConfiguration getRedisClusterConfiguration(){
if (StringUtils.isEmpty(redisClusterNotes)){
log.error("redis集群节点为空");
throw new RuntimeException();
}
String[] hostAndPorts = redisClusterNotes.split(",");
Set<RedisNode> nodes = new HashSet<>();
for (String hostAndPort : hostAndPorts){
String[] ipAndPort = hostAndPort.split(":");
nodes.add(new RedisNode(ipAndPort[0],Integer.parseInt(ipAndPort[1])));
}
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
redisClusterConfiguration.setClusterNodes(nodes);
redisClusterConfiguration.setMaxRedirects(maxRedirects);
return redisClusterConfiguration;
}
@Bean(name = "jedisConnectionFactory")
public JedisConnectionFactory jedisConnectionFactory(@Qualifier("redisClusterConfiguration") RedisClusterConfiguration redisClusterConfiguration,
@Qualifier("jedisPoolConfig") JedisPoolConfig jedisPoolConfig) {
//集群模式
JedisConnectionFactory factory = new JedisConnectionFactory(redisClusterConfiguration,jedisPoolConfig);
factory.setPassword(password);
return factory;
}
@Bean(name = "jedisCluster")
public JedisCluster getJedisCluster(@Qualifier("jedisPoolConfig") JedisPoolConfig jedisPoolConfig){
String[] hostAndPorts = redisClusterNotes.split(",");
Set<HostAndPort> nodes = new HashSet<>();
for (String hostAndPort : hostAndPorts){
String[] ipAndPort = hostAndPort.split(":");
nodes.add(new HostAndPort(ipAndPort[0],Integer.parseInt(ipAndPort[1])));
}
JedisCluster jedisCluster = new JedisCluster(nodes,timeout,1000,3,password, jedisPoolConfig);
Map<String,JedisPool> node = jedisCluster.getClusterNodes();
return jedisCluster;
}
@Bean(name = "redisTemplate")
public RedisTemplate redisTemplate(@Qualifier("jedisConnectionFactory") JedisConnectionFactory jedisConnectionFactory){
StringRedisTemplate redisTemplate = new StringRedisTemplate();
redisTemplate.setConnectionFactory(jedisConnectionFactory);
return redisTemplate;
}
public String getPreFixKey(String key){
return String.format("%s:%s",namespace,key);
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public int getMaxtotal() {
return maxtotal;
}
public void setMaxtotal(int maxtotal) {
this.maxtotal = maxtotal;
}
public int getMaxidle() {
return maxidle;
}
public void setMaxidle(int maxidle) {
this.maxidle = maxidle;
}
public int getMinidle() {
return minidle;
}
public void setMinidle(int minidle) {
this.minidle = minidle;
}
public int getMaxwaitmillis() {
return maxwaitmillis;
}
public void setMaxwaitmillis(int maxwaitmillis) {
this.maxwaitmillis = maxwaitmillis;
}
public int getSoTimeout() {
return soTimeout;
}
public void setSoTimeout(int soTimeout) {
this.soTimeout = soTimeout;
}
public int getMaxAttempts() {
return maxAttempts;
}
public void setMaxAttempts(int maxAttempts) {
this.maxAttempts = maxAttempts;
}
public int getMaxRedirects() {
return maxRedirects;
}
public void setMaxRedirects(int maxRedirects) {
this.maxRedirects = maxRedirects;
}
public String getRedisClusterNotes() {
return redisClusterNotes;
}
public void setRedisClusterNotes(String redisClusterNotes) {
this.redisClusterNotes = redisClusterNotes;
}
}
redisCluster API
@Log4j2
@Component
public class CacheApi {
@Resource
CacheConfig cacheConfig;
public void expire(JedisCluster jedisCluster,String key, int seconds) {
try {
jedisCluster.expire(cacheConfig.getPreFixKey(key), seconds);
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
} catch (JedisDataException e) {
log.error("JedisDataException",e);
}
}
public <T extends Serializable> T getCache(JedisCluster jedisCluster,String key) {
log.info("===========getCache===========key:"+key);
try {
byte[] result = jedisCluster.get(cacheConfig.getPreFixKey(key).getBytes());
if (null==result ) {
return null;
}
ByteArrayInputStream bis = new ByteArrayInputStream(result);
try (ObjectInputStream ois = new ObjectInputStream(bis)) {
return (T) ois.readObject();
} catch (ClassNotFoundException e) {
log.error("对象类型不存在", e);
} catch (IOException e) {
log.error("对象类型不存在", e);
}
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
//连接超时异常,则返回不再推送
//String str = "timeout";
//return (T) str;
}
return null;
}
public <T extends Serializable> List<T> getCache(JedisCluster jedisCluster,String... keys) {
if (ArrayUtils.isEmpty(keys)) {
return new ArrayList<>();
}
List<T> resultList = new ArrayList<>(keys.length);
try {
for (String key : keys) {
byte[] result = jedisCluster.get(cacheConfig.getPreFixKey(key).getBytes());
if (null==result) {
resultList.add(null);
} else {
ByteArrayInputStream bis = new ByteArrayInputStream(result);
try (ObjectInputStream ois = new ObjectInputStream(bis)) {
resultList.add((T) ois.readObject());
} catch (ClassNotFoundException e) {
resultList.add(null);
} catch (IOException e) {
resultList.add(null);
}
}
}
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
return resultList;
}
public <T extends Serializable> List<T> getCache(JedisCluster jedisCluster,List<String> keys) {
if (CollectionUtils.isEmpty(keys)) {
return new ArrayList<>();
}
List<T> resultList = new ArrayList<>(keys.size());
try {
for (String key : keys) {
byte[] result = jedisCluster.get(cacheConfig.getPreFixKey(key).getBytes());
if (null==result) {
resultList.add(null);
} else {
ByteArrayInputStream bis = new ByteArrayInputStream(result);
try (ObjectInputStream ois = new ObjectInputStream(bis)) {
resultList.add((T) ois.readObject());
} catch (ClassNotFoundException e) {
log.error(e.getLocalizedMessage(),e);
resultList.add(null);
} catch (IOException e) {
log.error(e.getLocalizedMessage(),e);
resultList.add(null);
}
}
}
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
return resultList;
}
public Long incr(JedisCluster jedisCluster,String key,Integer liveSeconds ) {
try {
if (null==liveSeconds ) {
return jedisCluster.incr(key);
} else {
long result = jedisCluster.incr(cacheConfig.getPreFixKey(key));
jedisCluster.expire(cacheConfig.getPreFixKey(key), liveSeconds);
return result;
}
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
} catch (JedisDataException e) {
log.error("JedisDataException",e);
}
return null;
}
public Long incrGetCache(JedisCluster jedisCluster,String key) {
try {
String result = jedisCluster.get(cacheConfig.getPreFixKey(key));
if (null==result ) {
return null;
}
return Long.valueOf(result);
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
return 0L;
}
public List<Long> incrGetCache(JedisCluster jedisCluster,String... keys) {
if (ArrayUtils.isEmpty(keys)) {
return new ArrayList<>();
}
List<Long> resultList = new ArrayList<>(keys.length);
try {
for (String key : keys) {
String result = jedisCluster.get(cacheConfig.getPreFixKey(key));
if (null==result ) {
resultList.add(null);
} else {
resultList.add(Long.valueOf(result));
}
}
return resultList;
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
return resultList;
}
public List<Long> incrGetCache(JedisCluster jedisCluster,List<String> keys) {
if (CollectionUtils.isEmpty(keys)) {
return new ArrayList<>();
}
List<Long> resultList = new ArrayList<>(keys.size());
try {
for (String key : keys) {
String result = jedisCluster.get(cacheConfig.getPreFixKey(key));
if (null==result ) {
resultList.add(null);
} else {
resultList.add(Long.valueOf(result));
}
}
return resultList;
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
return resultList;
}
public Long incrNoExp(JedisCluster jedisCluster,String key) {
try {
long result = jedisCluster.incr(cacheConfig.getPreFixKey(key));
return result;
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
} catch (JedisDataException e) {
log.error("JedisDataException",e);
}
return null;
}
public void incrPutCache(JedisCluster jedisCluster,String key, long value,Integer liveSeconds ) {
try {
if (null==liveSeconds ) {
jedisCluster.setnx(cacheConfig.getPreFixKey(key), String.valueOf(value));
} else {
jedisCluster.setex(cacheConfig.getPreFixKey(key), liveSeconds, String.valueOf(value));
}
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
}
public void putCache(JedisCluster jedisCluster,String[] keys, Object[] values,Integer liveSeconds) {
if (ArrayUtils.isEmpty(keys) || ArrayUtils.isEmpty(values) || keys.length != values.length) {
return;
}
JedisClusterPipeline jcp = JedisClusterPipeline.pipelined(jedisCluster);
jcp.refreshCluster();
try {
for (int i = 0; i < keys.length; i++) {
byte[] key = cacheConfig.getPreFixKey(keys[i]).getBytes();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(values[i]);
oos.flush();
if (null==liveSeconds ) {
jcp.setnx(key, bos.toByteArray());
} else {
jcp.setex(key, liveSeconds, bos.toByteArray());
}
} catch (IOException e) {
log.error("对象缓存失败", e);
}
}
jcp.sync();
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}finally {
jcp.close();
}
}
public void putCache(JedisCluster jedisCluster,List<String> keys, List<Object> values,Integer liveSeconds) {
if (CollectionUtils.isEmpty(keys) || CollectionUtils.isEmpty(values) || keys.size() != values.size()) {
return;
}
JedisClusterPipeline jcp = JedisClusterPipeline.pipelined(jedisCluster);
jcp.refreshCluster();
try {
for (int i = 0; i < keys.size(); i++) {
byte[] key = cacheConfig.getPreFixKey(keys.get(i)).getBytes();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(values.get(i));
oos.flush();
if (null==liveSeconds ) {
jcp.setnx(key, bos.toByteArray());
} else {
jcp.setex(key, liveSeconds, bos.toByteArray());
}
} catch (IOException e) {
log.error("对象缓存失败", e);
}
}
jcp.sync();
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}finally {
jcp.close();
}
}
public void zaddCache(JedisCluster jedisCluster,String key, Map<String, Double> scoreMembers) {
if (StringUtils.isEmpty(key)||CollectionUtils.isEmpty(scoreMembers) ) {
return;
}
try {
jedisCluster.zadd(cacheConfig.getPreFixKey(key),scoreMembers);
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
}
public void zaddCache(JedisCluster jedisCluster,String key, String value,Double score) {
if (StringUtils.isEmpty(key)||StringUtils.isEmpty(value) ) {
return;
}
try {
jedisCluster.zadd(cacheConfig.getPreFixKey(key),score,value);
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
}
/**
* 根据key查询存入缓存的排序map(含score)
*
* @param jedisCluster
* @param key
* @param start
* @param end
* @param isInverted: 查询结果是否倒排
* @return*/
public Map<String, Double> zrangeWithScores(JedisCluster jedisCluster,String key, Integer start, Integer end,
Boolean isInverted) {
// 使用LinkedHashMap保证map中的顺序按key的插入顺序排列
Map<String, Double> result = new LinkedHashMap<String, Double>();
List<String> keyList = new ArrayList<String>();
List<Double> valueList = new ArrayList<Double>();
start = start == null ? 0 : start;
end = end == null ? -1 : end;
// 查询结果是否倒排,默认为false
isInverted = isInverted == null ? false : isInverted;
try {
Set<Tuple> set = jedisCluster.zrangeWithScores(cacheConfig.getPreFixKey(key), start, end);
if (set != null && !set.isEmpty()) {
for (Tuple tuple : set) {
keyList.add(tuple.getElement());
valueList.add(tuple.getScore());
}
if (isInverted) {
// 将key-value结果倒排
Collections.reverse(keyList);
Collections.reverse(valueList);
}
for (int i = 0; i < keyList.size(); i++) {
result.put(keyList.get(i), valueList.get(i));
}
}
return result;
} catch (JedisConnectionException e) {
log.error("JedisConnectionException", e);
return null;
}
}
/**
* 根据key查询存入缓存的排序map-key(不含score)
*
* @param jedisCluster
* @param key
* @param start
* @param end
* @param isInverted: 查询结果是否倒排
* @return*/
public List<String> zrangeList(JedisCluster jedisCluster,String key, Integer start, Integer end,
Boolean isInverted) {
List<String> result = new ArrayList<String>();
start = start == null ? 0 : start;
end = end == null ? -1 : end;
// 查询结果是否倒排,默认为false
isInverted = isInverted == null ? false : isInverted;
try {
Set<String> set = jedisCluster.zrange(cacheConfig.getPreFixKey(key), start, end);
if (set != null && !set.isEmpty()) {
result.addAll(set);
if (isInverted) {
Collections.reverse(result);
}
}
return result;
} catch (JedisConnectionException e) {
log.error("JedisConnectionException", e);
return null;
}
}
public void zremPreFixKeyCache(JedisCluster jedisCluster,String key,String member) {
if (StringUtils.isEmpty(key)||StringUtils.isEmpty(member)) {
return;
}
try {
jedisCluster.zrem(key,member);
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
}
public void zremCache(JedisCluster jedisCluster,String key,String member) {
if (StringUtils.isEmpty(key)||StringUtils.isEmpty(member)) {
return;
}
try {
jedisCluster.zrem(cacheConfig.getPreFixKey(key),member);
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
}
public Long zcardCache(JedisCluster jedisCluster,String key) {
if (StringUtils.isEmpty(key)) {
return 0L;
}
try {
return jedisCluster.zcard(cacheConfig.getPreFixKey(key));
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
return 0L;
}
public <T extends Serializable> void putCache(JedisCluster jedisCluster,String key, T object,Integer liveSeconds) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
if (null==liveSeconds ) {
jedisCluster.setnx(cacheConfig.getPreFixKey(key).getBytes(), bos.toByteArray());
} else {
jedisCluster.setex(cacheConfig.getPreFixKey(key).getBytes(), liveSeconds, bos.toByteArray());
}
} catch (IOException e) {
log.error("对象缓存失败", e);
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
}
}
public boolean removeCache(JedisCluster jedisCluster) {
throw new UnsupportedOperationException();
}
public boolean removeCache(JedisCluster jedisCluster,String key) {
try {
jedisCluster.del(cacheConfig.getPreFixKey(key));
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
return false;
}
return true;
}
public boolean removeCache(JedisCluster jedisCluster,String key, int seconds) {
try {
jedisCluster.expire(cacheConfig.getPreFixKey(key), seconds);
} catch (JedisConnectionException e) {
log.error("JedisConnectionException",e);
return false;
}
return true;
}
}
这这里说明一下,因为redisCluster的api执行最后都要执行releaseConnection方法,自动关闭jedis连接,所以不用手动关闭。
private void releaseConnection(Jedis connection) {
if (connection != null) {
connection.close();
}
}
redis集群是不支持批量操作的,这方面的知识博客上一大堆,所以在这里就不详细说明了,至于如何使用我下面贴出使用批量操作的工具类。直接在代码中使用即可。
@Log4j2
public class JedisClusterPipeline extends PipelineBase implements Closeable{
// 部分字段没有对应的获取方法,只能采用反射来做
// 你也可以去继承JedisCluster和JedisSlotBasedConnectionHandler来提供访问接口
private static final Field FIELD_CONNECTION_HANDLER;
private static final Field FIELD_CACHE;
static {
FIELD_CONNECTION_HANDLER = getField(BinaryJedisCluster.class, "connectionHandler");
FIELD_CACHE = getField(JedisClusterConnectionHandler.class, "cache");
}
private JedisSlotBasedConnectionHandler connectionHandler;
private JedisClusterInfoCache clusterInfoCache;
private Queue<Client> clients = new LinkedList<Client>(); // 根据顺序存储每个命令对应的Client
private Map<JedisPool, Jedis> jedisMap = new HashMap<>(); // 用于缓存连接
private boolean hasDataInBuf = false; // 是否有数据在缓存区
/**
* 根据jedisCluster实例生成对应的JedisClusterPipeline
* @param
* @return
*/
public static JedisClusterPipeline pipelined(JedisCluster jedisCluster) {
JedisClusterPipeline pipeline = new JedisClusterPipeline();
pipeline.setJedisCluster(jedisCluster);
return pipeline;
}
public JedisClusterPipeline() {
}
public void setJedisCluster(JedisCluster jedis) {
connectionHandler = getValue(jedis, FIELD_CONNECTION_HANDLER);
clusterInfoCache = getValue(connectionHandler, FIELD_CACHE);
}
/**
* 刷新集群信息,当集群信息发生变更时调用
* @param
* @return
*/
public void refreshCluster() {
connectionHandler.renewSlotCache();
}
/**
* 同步读取所有数据. 与syncAndReturnAll()相比,sync()只是没有对数据做反序列化
*/
public void sync() {
innerSync(null);
}
/**
* 同步读取所有数据 并按命令顺序返回一个列表
*
* @return 按照命令的顺序返回所有的数据
*/
public List<Object> syncAndReturnAll() {
List<Object> responseList = new ArrayList<Object>();
innerSync(responseList);
return responseList;
}
private void innerSync(List<Object> formatted) {
HashSet<Client> clientSet = new HashSet<Client>();
try {
for (Client client : clients) {
// 在sync()调用时其实是不需要解析结果数据的,但是如果不调用get方法,发生了JedisMovedDataException这样的错误应用是不知道的,因此需要调用get()来触发错误。
// 其实如果Response的data属性可以直接获取,可以省掉解析数据的时间,然而它并没有提供对应方法,要获取data属性就得用反射,不想再反射了,所以就这样了
Object data = generateResponse(client.getOne()).get();
if (null != formatted) {
formatted.add(data);
}
// size相同说明所有的client都已经添加,就不用再调用add方法了
if (clientSet.size() != jedisMap.size()) {
clientSet.add(client);
}
}
} catch (JedisRedirectionException jre) {
if (jre instanceof JedisMovedDataException) {
// if MOVED redirection occurred, rebuilds cluster's slot cache,
// recommended by Redis cluster specification
refreshCluster();
}
throw jre;
} finally {
if (clientSet.size() != jedisMap.size()) {
// 所有还没有执行过的client要保证执行(flush),防止放回连接池后后面的命令被污染
for (Jedis jedis : jedisMap.values()) {
if (clientSet.contains(jedis.getClient())) {
continue;
}
flushCachedData(jedis);
}
}
hasDataInBuf = false;
close();
}
}
@Override
public void close() {
clean();
clients.clear();
for (Jedis jedis : jedisMap.values()) {
if (hasDataInBuf) {
flushCachedData(jedis);
}
jedis.close();
}
jedisMap.clear();
hasDataInBuf = false;
}
private void flushCachedData(Jedis jedis) {
try {
jedis.getClient().getAll();
} catch (RuntimeException ex) {
}
}
@Override
protected Client getClient(String key) {
byte[] bKey = SafeEncoder.encode(key);
return getClient(bKey);
}
@Override
protected Client getClient(byte[] key) {
Jedis jedis = getJedis(JedisClusterCRC16.getSlot(key));
Client client = jedis.getClient();
clients.add(client);
return client;
}
private Jedis getJedis(int slot) {
JedisPool pool = clusterInfoCache.getSlotPool(slot);
// 根据pool从缓存中获取Jedis
Jedis jedis = jedisMap.get(pool);
if (null == jedis) {
jedis = pool.getResource();
jedisMap.put(pool, jedis);
}
hasDataInBuf = true;
return jedis;
}
private static Field getField(Class<?> cls, String fieldName) {
try {
Field field = cls.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException | SecurityException e) {
throw new RuntimeException("cannot find or access field '" + fieldName + "' from " + cls.getName(), e);
}
}
@SuppressWarnings({"unchecked" })
private static <T> T getValue(Object obj, Field field) {
try {
return (T)field.get(obj);
} catch (IllegalArgumentException | IllegalAccessException e) {
log.error("get value fail", e);
throw new RuntimeException(e);
}
}
}