转载请注明出处:https://blog.csdn.net/l1028386804/article/details/82597154
使用Cacheable注解Redis方法时,如果Redis服务器挂了,就直接抛出异常了,
java.net.ConnectException: Connection refused: connect
那么,有没有什么办法可以继续向下执行方法,从相关的数据库中查询数据,而不是直接抛出异常导致整个程序终止运行呢?
经过反复翻看Spring的源码和相关资料,并经过不断验证,得出了答案:有相关的方案!!!
解决方案就是重写CachingConfigurerSupport中的四个方法:
package org.springframework.cache.annotation;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
/**
* An implementation of {@link CachingConfigurer} with empty methods allowing
* sub-classes to override only the methods they're interested in.
*
* @author Stephane Nicoll
* @since 4.1
* @see CachingConfigurer
*/
public class CachingConfigurerSupport implements CachingConfigurer {
@Override
public CacheManager cacheManager() {
return null;
}
@Override
public KeyGenerator keyGenerator() {
return null;
}
@Override
public CacheResolver cacheResolver() {
return null;
}
@Override
public CacheErrorHandler errorHandler() {
return null;
}
}
具体如下:
1、BaseRedisConfig类
package io.mykit.cache.redis.spring.annotation.config;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachingConfigurerSupport;
/**
* @author liuyazhuang
* @version 1.0.0
* @date 2018/8/21 18:48
* @description Redis集群配置基础类
*/
@Data
public class BaseRedisConfig extends CachingConfigurerSupport {
@Value("${redis.cluster.max.total}")
protected Integer maxTotal;
@Value("${redis.cluster.max.idle}")
protected Integer maxIdle;
@Value("${redis.cluster.min.idle}")
protected Integer minIdle;
@Value("${redis.cluster.timeout}")
protected Integer timeout;
@Value("${redis.cluster.maxAttempts}")
protected Integer maxAttempts;
@Value("${redis.cluster.redisDefaultExpiration}")
protected Integer redisDefaultExpiration;
@Value("${redis.cluster.usePrefix}")
protected Boolean usePrefix;
@Value("${redis.cluster.blockWhenExhausted}")
protected Boolean blockWhenExhausted;
@Value("${redis.cluster.maxWaitMillis}")
protected Integer maxWaitMillis;
@Value("${redis.cluster.testOnBorrow}")
protected Boolean testOnBorrow;
@Value("${redis.cluster.testOnReturn}")
protected Boolean testOnReturn;
@Value("${redis.cluster.testWhileIdle}")
protected Boolean testWhileIdle;
@Value("${redis.cluster.minEvictableIdleTimeMillis}")
protected Integer minEvictableIdleTimeMillis;
@Value("${redis.cluster.timeBetweenEvictionRunsMillis}")
protected Integer timeBetweenEvictionRunsMillis;
@Value("${redis.cluster.numTestsPerEvictionRun}")
protected Integer numTestsPerEvictionRun;
@Value("${redis.cluster.password}")
protected String password;
@Value("${redis.cluster.defaultExpirationKey}")
protected String defaultExpirationKey;
@Value("${redis.cluster.expirationSecondTime}")
protected Integer expirationSecondTime;
@Value("${redis.cluster.preloadSecondTime}")
protected Integer preloadSecondTime;
@Value("${redis.cluster.index.zero}")
protected Integer zero;
@Value("${redis.cluster.index.one}")
protected Integer one;
@Value("${redis.cluster.index.two}")
protected Integer two;
@Value("${redis.cluster.index.three}")
protected Integer three;
@Value("${redis.cluster.node.one}")
protected String nodeOne;
@Value("${redis.cluster.node.one.port}")
protected Integer nodeOnePort;
@Value("${redis.cluster.node.two}")
protected String nodeTwo;
@Value("${redis.cluster.node.two.port}")
protected Integer nodeTwoPort;
@Value("${redis.cluster.node.three}")
protected String nodeThree;
@Value("${redis.cluster.node.three.port}")
protected Integer nodeThreePort;
@Value("${redis.cluster.node.four}")
protected String nodeFour;
@Value("${redis.cluster.node.four.port}")
protected Integer nodeFourPort;
@Value("${redis.cluster.node.five}")
protected String nodeFive;
@Value("${redis.cluster.node.five.port}")
protected Integer nodeFivePort;
@Value("${redis.cluster.node.six}")
protected String nodeSix;
@Value("${redis.cluster.node.six.port}")
protected Integer nodeSixPort;
@Value("${redis.cluster.node.seven}")
protected String nodeSeven;
@Value("${redis.cluster.node.seven.port}")
protected Integer nodeSevenPort;
@Override
public String toString(){
return JSONObject.toJSONString(this);
}
}
2、CacheRedisConfig类
package io.mykit.cache.redis.spring.annotation.config;
import com.alibaba.fastjson.parser.ParserConfig;
import io.mykit.cache.redis.spring.aspect.CachingAnnotationsAspect;
import io.mykit.cache.redis.spring.cache.CacheKeyGenerator;
import io.mykit.cache.redis.spring.cache.CacheTime;
import io.mykit.cache.redis.spring.cache.CustomizedRedisCacheManager;
import io.mykit.cache.redis.spring.serializer.FastJsonRedisSerializer;
import io.mykit.cache.redis.spring.serializer.StringRedisSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author liuyazhuang
* @version 1.0.0
* @date 2018/8/21 19:06
* @description Redis配置类
*/
@Slf4j
public class CacheRedisConfig extends BaseRedisConfig{
/**
* 配置 JedisPoolConfig
* @return JedisPoolConfig对象
*/
@Bean
public JedisPoolConfig jedisPoolConfig(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxTotal);
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
jedisPoolConfig.setBlockWhenExhausted(blockWhenExhausted);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setTestOnBorrow(testOnBorrow);
jedisPoolConfig.setTestOnReturn(testOnReturn);
jedisPoolConfig.setTestWhileIdle(testWhileIdle);
jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
return jedisPoolConfig;
}
/**
* 配置 RedisClusterConfiguration
* @return RedisClusterConfiguration对象
*/
@Bean
public RedisClusterConfiguration redisClusterConfiguration(){
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
redisClusterConfiguration.setMaxRedirects(3);
redisClusterConfiguration.setClusterNodes(getRedisNodes());
return redisClusterConfiguration;
}
/**
* 配置 JedisConnectionFactory
* @return 返回JedisConnectionFactory对象
*/
@Bean
public JedisConnectionFactory jedisConnectionFactory(){
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration(), jedisPoolConfig());
jedisConnectionFactory.setPassword(password);
jedisConnectionFactory.setTimeout(timeout);
return jedisConnectionFactory;
}
/**
* 配置RedisTemplate
* @return RedisTemplate对象
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(){
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
StringRedisSerializer keySerializer = new StringRedisSerializer();
FastJsonRedisSerializer<Object> valueSerializer = new FastJsonRedisSerializer<Object>();
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
redisTemplate.setKeySerializer(keySerializer);
redisTemplate.setValueSerializer(valueSerializer);
redisTemplate.setHashKeySerializer(keySerializer);
redisTemplate.setHashValueSerializer(valueSerializer);
return redisTemplate;
}
/**
* 配置CacheAnnotationTime
* @return CacheAnnotationTime对象
*/
@Bean
public CacheTime cacheTime(){
CacheTime cacheTime = new CacheTime(expirationSecondTime, preloadSecondTime);
return cacheTime;
}
/**
* 配置 CacheAnnotationKeyGenerator
* @return CacheAnnotationKeyGenerator对象
*/
@Bean
public CacheKeyGenerator cacheKeyGenerator(){
CacheKeyGenerator cacheKeyGenerator = new CacheKeyGenerator();
return cacheKeyGenerator;
}
/**
* 配置SpringCachingAnnotationsAspect
* @return SpringCachingAnnotationsAspect对象
*/
@Bean
public CachingAnnotationsAspect cachingAnnotationsAspect(){
CachingAnnotationsAspect cachingAnnotationsAspect = new CachingAnnotationsAspect();
return cachingAnnotationsAspect;
}
/**
* 配置CustomizedAnnotationRedisCacheManager
* @return CustomizedAnnotationRedisCacheManager对象
*/
@Bean
public CustomizedRedisCacheManager customizedRedisCacheManager(){
CustomizedRedisCacheManager customizedAnnotationRedisCacheManager = new CustomizedRedisCacheManager(redisTemplate());
customizedAnnotationRedisCacheManager.setDefaultExpiration(redisDefaultExpiration);
customizedAnnotationRedisCacheManager.setUsePrefix(usePrefix);
Map<String, CacheTime> map = new HashMap<String, CacheTime>();
map.put(defaultExpirationKey, cacheTime());
customizedAnnotationRedisCacheManager.setCacheTimes(map);
return customizedAnnotationRedisCacheManager;
}
/**
* 封装各Redis节点信息
* @return Redis节点Set集合
*/
private Set<RedisNode> getRedisNodes(){
Set<RedisNode> set = new HashSet<RedisNode>();
RedisNode redisNode1 = new RedisNode(nodeOne, nodeOnePort);
set.add(redisNode1);
RedisNode redisNode2 = new RedisNode(nodeTwo, nodeTwoPort);
set.add(redisNode2);
RedisNode redisNode3 = new RedisNode(nodeThree, nodeThreePort);
set.add(redisNode3);
RedisNode redisNode4 = new RedisNode(nodeFour, nodeFourPort);
set.add(redisNode4);
RedisNode redisNode5 = new RedisNode(nodeFive, nodeFivePort);
set.add(redisNode5);
RedisNode redisNode6 = new RedisNode(nodeSix, nodeSixPort);
set.add(redisNode6);
RedisNode redisNode7 = new RedisNode(nodeSeven, nodeSevenPort);
set.add(redisNode7);
return set;
}
@Override
public CacheManager cacheManager() {
return customizedRedisCacheManager();
}
@Override
public KeyGenerator keyGenerator() {
return cacheKeyGenerator();
}
@Override
public CacheResolver cacheResolver() {
return super.cacheResolver();
}
@Override
public CacheErrorHandler errorHandler() {
CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
@Override
public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
RedisErrorException(exception, key);
}
@Override
public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
RedisErrorException(exception, key);
}
@Override
public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
RedisErrorException(exception, key);
}
@Override
public void handleCacheClearError(RuntimeException exception, Cache cache) {
RedisErrorException(exception, null);
}
};
return cacheErrorHandler;
}
protected void RedisErrorException(Exception exception,Object key){
log.error("redis异常:key=[{}], exception={}", key, exception.getMessage());
}
}
问题解决。