Spring @Cacheable redis異常不影響正常業(yè)務(wù)方案
背景
項目中,使用@Cacheable進(jìn)行數(shù)據(jù)緩存。發(fā)現(xiàn):當(dāng)redis宕機(jī)之后,@Cacheable注解的方法并未進(jìn)行緩存沖突,而是直接拋出異常。而這樣的異常會導(dǎo)致服務(wù)不可用。
原因分析
我們是通過@EnableCaching進(jìn)行緩存啟用的,因此可以先看@EnableCaching的相關(guān)注釋

通過@EnableCaching的類注釋可發(fā)現(xiàn),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方法可配置異常的處理方式。通過該方法上的注釋可以發(fā)現(xiàn),默認(rèn)的CacheErrorHandler實現(xiàn)類是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的異常不做任何處理,直接將該異常拋給客戶端。因此默認(rèn)的情況下,redis服務(wù)器異常后,直接就阻斷了正常業(yè)務(wù)
解決方案
通過上面的分析可知,我們可以通過自定義CacheErrorHandler來干預(yù)@Cacheable的異常處理邏輯。具體代碼如下:
public class RedisConfig extends CachingConfigurerSupport {
/**
* redis數(shù)據(jù)操作異常處理。該方法處理邏輯:在日志中打印出錯誤信息,但是放行。
* 保證redis服務(wù)器出現(xiàn)連接等問題的時候不影響程序的正常運行
*/
@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);
}
}
到此這篇關(guān)于Spring @Cacheable redis異常不影響正常業(yè)務(wù)方案的文章就介紹到這了,更多相關(guān)Spring @Cacheable redis異常內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java equals 方法與hashcode 方法的深入解析
面試時經(jīng)常會問起字符串比較相關(guān)的問題,比如:字符串比較時用的什么方法,內(nèi)部實現(xiàn)如何?hashcode的作用,以及重寫equal方法,為什么要重寫hashcode方法?以下就為大家解答,需要的朋友可以參考下2013-07-07
Java中ShardingSphere分庫分表實戰(zhàn)
我們做項目的時候,數(shù)據(jù)量比較大,單表千萬級別的,需要分庫分表,本文主要介紹了Java中ShardingSphere分庫分表實戰(zhàn),感興趣的可以了解一下2021-09-09
JavaWeb三大組件之監(jiān)聽器Listener詳解
這篇文章主要介紹了JavaWeb三大組件之監(jiān)聽器Listener詳解,在JavaWeb應(yīng)用程序中,Listener監(jiān)聽器是一種機(jī)制,用于監(jiān)聽和響應(yīng)特定的事件,它可以感知并響應(yīng)與應(yīng)用程序相關(guān)的事件,從而執(zhí)行相應(yīng)的邏輯處理,需要的朋友可以參考下2023-10-10
Java 數(shù)組轉(zhuǎn)List的四種方式小結(jié)
本文主要介紹了四種將Java數(shù)組轉(zhuǎn)換為List的方法,包括使用Arrays.asList、ArrayList構(gòu)造器、Collections.addAll以及JDK8的Stream,具有一定的參考價值,感興趣的可以了解一下2024-10-10
java設(shè)計簡單學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java設(shè)計簡單學(xué)生管理系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-09-09

