Spring @Cacheable redis异常不影响正常业务方案

背景

项目中,使用@Cacheable进行数据缓存。发现:当redis宕机之后,@Cacheable注解的方法并未进行缓存冲突,而是直接抛出异常。而这样的异常会导致服务不可用。

原因分析

我们是通过@EnableCaching进行缓存启用的,因此可以先看@EnableCaching的相关注释

通过@EnableCaching的类注释可发现,spring cache的核心配置接口为:org.springframework.cache.annotation.CachingConfigurer

/**
 * Interface to be implemented by @{@link org.springframework.context.annotation.Configuration
 * Configuration} classes annotated with @{@link EnableCaching} that wish or need to
 * specify explicitly how caches are resolved and how keys are generated for annotation-driven
 * cache management. Consider extending {@link CachingConfigurerSupport}, which provides a
 * stub implementation of all interface methods.
 *
 * <p>See @{@link EnableCaching} for general examples and context; see
 * {@link #cacheManager()}, {@link #cacheResolver()} and {@link #keyGenerator()}
 * for detailed instructions.
 *
 * @author Chris Beams
 * @author Stephane Nicoll
 * @since 3.1
 * @see EnableCaching
 * @see CachingConfigurerSupport
 */
public interface CachingConfigurer {

 /**
 * Return the cache manager bean to use for annotation-driven cache
 * management. A default {@link CacheResolver} will be initialized
 * behind the scenes with this cache manager. For more fine-grained
 * management of the cache resolution, consider setting the
 * {@link CacheResolver} directly.
 * <p>Implementations must explicitly declare
 * {@link org.springframework.context.annotation.Bean @Bean}, e.g.
 * <pre class="code">
 * Configuration
 * EnableCaching
 * public class AppConfig extends CachingConfigurerSupport {
 *  Bean // important!
 *  Override
 *  public CacheManager cacheManager() {
 *   // configure and return CacheManager instance
 *  }
 *  // ...
 * }
 * </pre>
 * See @{@link EnableCaching} for more complete examples.
 */
 CacheManager cacheManager();

 /**
 * Return the {@link CacheResolver} bean to use to resolve regular caches for
 * annotation-driven cache management. This is an alternative and more powerful
 * option of specifying the {@link CacheManager} to use.
 * <p>If both a {@link #cacheManager()} and {@code #cacheResolver()} are set,
 * the cache manager is ignored.
 * <p>Implementations must explicitly declare
 * {@link org.springframework.context.annotation.Bean @Bean}, e.g.
 * <pre class="code">
 * Configuration
 * EnableCaching
 * public class AppConfig extends CachingConfigurerSupport {
 *  Bean // important!
 *  Override
 *  public CacheResolver cacheResolver() {
 *   // configure and return CacheResolver instance
 *  }
 *  // ...
 * }
 * </pre>
 * See {@link EnableCaching} for more complete examples.
 */
 CacheResolver cacheResolver();

 /**
 * Return the key generator bean to use for annotation-driven cache management.
 * Implementations must explicitly declare
 * {@link org.springframework.context.annotation.Bean @Bean}, e.g.
 * <pre class="code">
 * Configuration
 * EnableCaching
 * public class AppConfig extends CachingConfigurerSupport {
 *  Bean // important!
 *  Override
 *  public KeyGenerator keyGenerator() {
 *   // configure and return KeyGenerator instance
 *  }
 *  // ...
 * }
 * </pre>
 * See @{@link EnableCaching} for more complete examples.
 */
 KeyGenerator keyGenerator();

 /**
 * Return the {@link CacheErrorHandler} to use to handle cache-related errors.
 * <p>By default,{@link org.springframework.cache.interceptor.SimpleCacheErrorHandler}
 * is used and simply throws the exception back at the client.
 * <p>Implementations must explicitly declare
 * {@link org.springframework.context.annotation.Bean @Bean}, e.g.
 * <pre class="code">
 * Configuration
 * EnableCaching
 * public class AppConfig extends CachingConfigurerSupport {
 *  Bean // important!
 *  Override
 *  public CacheErrorHandler errorHandler() {
 *   // configure and return CacheErrorHandler instance
 *  }
 *  // ...
 * }
 * </pre>
 * See @{@link EnableCaching} for more complete examples.
 */
 CacheErrorHandler errorHandler();

}

该接口errorHandler方法可配置异常的处理方式。通过该方法上的注释可以发现,默认的CacheErrorHandler实现类是org.springframework.cache.interceptor.SimpleCacheErrorHandler

/**
 * A simple {@link CacheErrorHandler} that does not handle the
 * exception at all, simply throwing it back at the client.
 *
 * @author Stephane Nicoll
 * @since 4.1
 */
public class SimpleCacheErrorHandler implements CacheErrorHandler {

 @Override
 public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
 throw exception;
 }

 @Override
 public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
 throw exception;
 }

 @Override
 public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
 throw exception;
 }

 @Override
 public void handleCacheClearError(RuntimeException exception, Cache cache) {
 throw exception;
 }
}

SimpleCacheErrorHandler类注释上说明的很清楚:对cache的异常不做任何处理,直接将该异常抛给客户端。因此默认的情况下,redis服务器异常后,直接就阻断了正常业务

解决方案

通过上面的分析可知,我们可以通过自定义CacheErrorHandler来干预@Cacheable的异常处理逻辑。具体代码如下:

public class RedisConfig extends CachingConfigurerSupport {

  /**
   * redis数据操作异常处理。该方法处理逻辑:在日志中打印出错误信息,但是放行。
   * 保证redis服务器出现连接等问题的时候不影响程序的正常运行
   */
  @Override
  public CacheErrorHandler errorHandler() {
    return new CacheErrorHandler() {
      @Override
      public void handleCachePutError(RuntimeException exception, Cache cache,
                      Object key, Object value) {
        handleRedisErrorException(exception, key);
      }

      @Override
      public void handleCacheGetError(RuntimeException exception, Cache cache,
                      Object key) {
        handleRedisErrorException(exception, key);
      }

      @Override
      public void handleCacheEvictError(RuntimeException exception, Cache cache,
                       Object key) {
        handleRedisErrorException(exception, key);
      }

      @Override
      public void handleCacheClearError(RuntimeException exception, Cache cache) {
        handleRedisErrorException(exception, null);
      }
    };
  }

  protected void handleRedisErrorException(RuntimeException exception, Object key) {
    log.error("redis异常:key=[{}]", key, exception);
  }
}

到此这篇关于Spring @Cacheable redis异常不影响正常业务方案的文章就介绍到这了,更多相关Spring @Cacheable redis异常内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • spring整合redis缓存并以注解(@Cacheable、@CachePut、@CacheEvict)形式使用

    maven项目中在pom.xml中依赖2个jar包,其他的spring的jar包省略: <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>org.springfra

  • Spring @Cacheable redis异常不影响正常业务方案

    背景 项目中,使用@Cacheable进行数据缓存.发现:当redis宕机之后,@Cacheable注解的方法并未进行缓存冲突,而是直接抛出异常.而这样的异常会导致服务不可用. 原因分析 我们是通过@EnableCaching进行缓存启用的,因此可以先看@EnableCaching的相关注释 通过@EnableCaching的类注释可发现,spring cache的核心配置接口为:org.springframework.cache.annotation.CachingConfigurer /**

  • Spring Cache+Redis缓存数据的实现示例

    目录 1.为什么使用缓存 2.常用的缓存注解 2.1 @Cacheable 2.2 @CacheEvict 2.3.@Cacheput 2.4.@Caching 2.5.@CacheConfig 3.SpringBoot缓存支持 4.项目继承Spring Cache+Redis 4.1 添加依赖 4.2 配置类 4.3 添加redis配置 4.4 接口中使用缓存注解 4.5 缓存效果测试 1.为什么使用缓存   我们知道内存的读取速度远大于硬盘的读取速度.当需要重复地获取相同数据时,一次一次地请

  • spring整合redis实现数据缓存的实例代码

    数据缓存原因:有些数据比较多,如果每次访问都要进行查询,无疑给数据库带来太大的负担,将一些庞大的查询数据并且更新次数较少的数据存入redis,能为系统的性能带来良好的提升. 业务逻辑思路:登入系统,访问数据时,检查redis是否有缓存,有则直接从redis中提取,没有则从数据库查询出,并存入redis中做缓存. 为什么要用redis做缓存: (1)异常快速:Redis的速度非常快,每秒能执行约11万集合,每秒约81000+条记录. (2)支持丰富的数据类型:Redis支持最大多数开发人员已经知道

  • 解决spring data redis的那些坑

    目录 spring data redis的那些坑 1. 使用lua脚本,返回类型解析错误 2. spring redis基于lettuce配置Client必须显示调用 spring data redis 的优缺点 spring data redis的那些坑 spring 的IOC很少有bug,AOPbug开始多起来,到了它的一些"玩具"一样的组件,bug无处不在.而且跟一般的开源框架不同,在github上你报告issue,会被"这不是一个bug"强行关闭.开一博文记

  • Spring @Cacheable指定失效时间实例

    目录 Spring @Cacheable指定失效时间 新版本配置 老版本配置 @Cacheable缓存失效时间策略默认实现及扩展 背景 Spring Cache Redis实现 Spring Cache 失效时间自行刷新 Spring @Cacheable指定失效时间 新版本配置 @Configuration @EnableCaching public class RedisCacheConfig { @Bean public RedisCacheManagerBuilderCustomizer

  • Redis异常测试盘点分析

    目录 Redis测试中的异常 一.更新 Key 异常 二.Key的删除和丢失 三.KEY 过期策略不当造成内存泄漏 四.查询Redis异常时处理 五.redis 穿透.击穿.雪崩 六.Redis死锁 SET Key UniqId Seconds 分布式Redis锁:Redlock 七.Redis持久化 八.缓存与数据库双写时的数据一致性 Redis测试中的异常 在测试工作中,涉及到与 redis 交互的场景变的越来越多了.关于redis本身就不作赘述了,网上随便搜,本人也做过一些整理. 今天只来

  • 解决Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程问题

    待解决的问题 Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程 解决办法 为spring session添加springSessionRedisTaskExecutor线程池. /** * 用于spring session,防止每次创建一个线程 * @return */ @Bean public ThreadPoolTaskExecutor springSessionRedisTaskExecutor(){ T

  • Spring整合redis(jedis)实现Session共享的过程

    今天来记录一下自己在整合框架过程中所遇到的问题: 1.    在用redis实现session共享时,项目启动报 No bean named 'springSessionRepositoryFilter' is defined 异常 2.    在调用缓存工具类的时候显示注入的JedisPool为Null (一个跟spring扫描有关的细节错误) 好了,开始上我整合的文件了 pom.xml依赖jar包 <!-- spring session begin --> <dependency&g

  • Spring boot redis cache的key的使用方法

    在数据库查询中我们往往会使用增加缓存来提高程序的性能,@Cacheable 可以方便的对数据库查询方法加缓存.本文主要来探究一下缓存使用的key. 搭建项目 数据库 mysql> select * from t_student; +----+--------+-------------+ | id | name | grade_class | +----+--------+-------------+ | 1 | Simone | 3-2 | +----+--------+-----------

  • 使用Spring Data Redis实现数据缓存的方法

    引言 目前很多系统为了解决数据读写的性能瓶颈,在系统架构设计中使用Redis实现缓存,Spring框架为了让开发人员更加方便快捷的使用Redis实现缓存,对Redis的操作进行了包装. 0.缓存 个人理解的缓存是指用于存储频繁使用的数据的空间,关注点是存储数据的空间和使用频繁的数据.缓存技术,简单的说就是先从缓存中查询数据是否存在,存在则直接返回,不存在再执行相应的操作获取数据,并将获取的数据存储到缓存中,它是一种提升系统性能的重要方法. 1.Redis Redis是一个开源的.内存存储key-

随机推荐