使用Cacheable注解Redis方法时,如果Redis服务器挂了 继续往下走的解决方案

时间:2022-06-19 14:38:35
使用Cacheable注解Redis方法时,如果Redis服务器挂了,就直接抛出异常了,
java.net.ConnectException: Connection refused: connect
有没可能在这个时候再往下走连接到数据库去获取值 而不是直接抛异常
答案是可以 被这个问题困扰了好久 终于实现了解决方案 解决方案就是重写CachingConfigurerSupport中的四个接口

使用Cacheable注解Redis方法时,如果Redis服务器挂了 继续往下走的解决方案

当然也可以按照自己的需求只重写errorHandler 接口 实现方法如下:

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

    /**
     * RedisConfig logger
     */
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Value("${spring.redis.timeout}")
    private int timeout;

    @Value("${spring.redis.password}")
    private String password;

    @Value("${spring.redis.database}")
    private int database;

    @Value("${spring.redis.pool.max-idle}")
    private int maxIdle;

    @Value("${spring.redis.pool.min-idle}")
    private int minIdle;

    /**
     * 注解@Cache key生成规则
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            public Object generate(Object target, Method method,
                    Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    };

    /**
     * 注解@Cache的管理器,设置过期时间的单位是秒
     *
     * @Description:
     * @param redisTemplate
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        Map<String, Long> expires = new HashMap<String, Long>();
        expires.put("User", 6000L);
        expires.put("city", 600L);
        cacheManager.setExpires(expires);
        cacheManager.setDefaultExpiration(600); // 设置key-value超时时间
        return cacheManager;
    }

    /**
     * redis模板,存储关键字是字符串,值是Jdk序列化
     *
     * @Description:
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
        redisTemplate.setConnectionFactory(factory);
        // key序列化方式;但是如果方法上有Long等非String类型的话,会报类型转换错误;
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();// Long类型不可以会出现异常信息;
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(redisSerializer);

        // JdkSerializationRedisSerializer序列方式;化
        JdkSerializationRedisSerializer jdkRedisSerializer = new JdkSerializationRedisSerializer();
        redisTemplate.setValueSerializer(jdkRedisSerializer);
        redisTemplate.setHashValueSerializer(jdkRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * redis连接的基础设置
     *
     * @Description:
     * @return
     */
    @Bean
    public JedisConnectionFactory redisConnectionFactory() {
        JedisConnectionFactory factory = new JedisConnectionFactory();
        factory.setHostName(host);
        factory.setPort(port);
        factory.setPassword(password);
        // 存储的库
        factory.setDatabase(database);
        // 设置连接超时时间
        factory.setTimeout(timeout);
        factory.setUsePool(true);
        factory.setPoolConfig(jedisPoolConfig());
        return factory;
    }

    /**
     * 连接池配置
     *
     * @Description:
     * @return
     */
    @Bean
    public JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIdle);
        return jedisPoolConfig;
    }

    /**
     * redis数据操作异常处理 这里的处理:在日志中打印出错误信息,但是放行
     * 保证redis服务器出现连接等问题的时候不影响程序的正常运行,使得能够出问题时不用缓存
     *
     * @return
     */
    @Bean
    @Override
    public CacheErrorHandler errorHandler() {
        CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
            
            @Override
            public void handleCachePutError(RuntimeException exception, Cache cache,
                    Object key, Object value) {
                RedisErrorException(exception, key);
            }
            
            @Override
            public void handleCacheGetError(RuntimeException exception, Cache cache,
                    Object key) {
                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){
        logger.error("redis异常:key=[{}]", key, exception);
    }
}