app开发者平台在数字化时代的重要性与发展趋势解析
940
2023-02-11
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.
*
*
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.
*
Implementations must explicitly declare
* {@link org.springframework.context.annotation.Bean @Bean}, e.g.
*
* Configuration
* EnableCaching
* public class AppConfig extends CachingConfigurerSupport {
* Bean // important!
* Override
* public CacheManager cacheManager() {
* // configure and return CacheManager instance
* }
* // ...
* }
*
* 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.
*
If both a {@link #cacheManager()} and {@code #cacheResolver()} are set,
* the cache manager is ignored.
*
Implementations must explicitly declare
* {@link org.springframework.context.annotation.Bean @Bean}, e.g.
*
* Configuration
* EnableCaching
* public class AppConfig extends CachingConfigurerSupport {
* Bean // important!
* Override
* public CacheResolver cacheResolver() {
* // configure and return CacheResolver instance
* }
* // ...
* }
*
* 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.
*
* Configuration
* EnableCaching
* public class AppConfig extends CachingConfigurerSupport {
* Bean // important!
* Override
* public KeyGenerator keyGenerator() {
* // configure and return KeyGenerator instance
* }
* // ...
* }
*
* See @{@link EnableCaching} for more complete examples.
*/
KeyGenerator keyGenerator();
/**
* Return the {@link CacheErrorHandler} to use to handle cache-related errors.
*
By default,{@link org.springframework.cache.interceptor.SimplxxKOBiYTjeCacheErrorHandhttp://ler}
* is used and simply throws the exception back at the client.
*
Implementations must explicitly declare
* {@link org.springframework.context.annotation.Bean @Bean}, e.g.
*
* Configuration
* EnableCaching
* public class AppConfig extends CachingConfigurerSupport {
* Bean // important!
* Override
* public CacheErrorHandler errorHandler() {
* // configure and return CacheErrorHandler instance
* }
* // ...
* }
*
* See @{@link EnableCaching} for more complete examples.
*/
CacheErrorHandler errorHandler();
}
该接口errorHandler方法可配置异常的处理方式。通过该方法上的注释可以发现,默认的CaxxKOBiYTjcheErrorHandler实现类是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);
}
}
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~