【问题标题】:How can I configure Spring Cache to ignore cache serialization errors?如何配置 Spring Cache 以忽略缓存序列化错误?
【发布时间】:2016-08-26 07:02:43
【问题描述】:

我使用带有 Redis / JDK 序列化的 Spring Cache 作为缓存后端。我有一个方法,它的结果被缓存并且缓存中填充了一些值。在对我的应用程序的更新中,我正在以一种破坏 Java 反序列化的方式更改缓存对象的类(将成员的类型从 List 更改为 Set)。现在对我的缓存方法的任何调用都会失败并显示org.springframework.data.redis.serializer.SerializationException

@Cacheable(cacheNames = "myCache", cacheManager = "myCacheManager)
public SomeObject myCachedMethod(String param) {
    return ...;
}

堆栈跟踪:

Caused by: org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.lang.ClassCastException: cannot assign instance of java.util.ArrayList to field SomeObject.foo of type java.util.Set in instance of SomeObject
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:41) ~[spring-data-redis-1.6.4.RELEASE.jar:na]
    at org.springframework.data.redis.cache.RedisCache$CacheValueAccessor.deserializeIfNecessary(RedisCache.java:378) ~[spring-data-redis-1.6.4.RELEASE.jar:na]
    at org.springframework.data.redis.cache.RedisCache.get(RedisCache.java:144) ~[spring-data-redis-1.6.4.RELEASE.jar:na]
    at org.springframework.data.redis.cache.RedisCache.get(RedisCache.java:94) ~[spring-data-redis-1.6.4.RELEASE.jar:na]
    at org.springframework.cache.interceptor.AbstractCacheInvoker.doGet(AbstractCacheInvoker.java:68) ~[spring-context-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.cache.interceptor.CacheAspectSupport.findInCaches(CacheAspectSupport.java:466) ~[spring-context-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.cache.interceptor.CacheAspectSupport.findCachedItem(CacheAspectSupport.java:432) ~[spring-context-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:336) ~[spring-context-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:302) ~[spring-context-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61) ~[spring-context-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-4.2.7.RELEASE.jar:4.2.7.RELEASE]
    at com.sun.proxy.$Proxy175.myCachedMethod(Unknown Source) ~[na:na]

有没有办法配置Spring缓存在反序列化对象时忽略错误并让方法调用通过?

【问题讨论】:

    标签: java spring caching


    【解决方案1】:

    看完Spring的代码找到了解决办法。

    缓存层处理发生在org.springframework.cache.interceptor.CacheErrorHandler 的实例中。默认情况下,Spring 使用org.springframework.cache.interceptor.SimpleCacheErrorHandler,它会抛出所有异常。为了放松这一点,可以扩展该类并记录/忽略缓存获取异常(这会导致它们像缓存未命中一样被处理):

    @Configuration
    @EnableCaching
    public class CacheConfiguration extends CachingConfigurerSupport {
        @Slf4j
        private static class RelaxedCacheErrorHandler extends SimpleCacheErrorHandler {
            @Override
            public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
                log.error("Error getting from cache.", exception);
            }
        }
    
        @Override
        public CacheErrorHandler errorHandler() {
            return new RelaxedCacheErrorHandler();
        }
    
        // More config...
    }
    

    【讨论】:

    • 如果在防止错误之后触发了某种断路器机制,那就太好了。因为如果对缓存方法的调用过多,所有响应至少会花费 Redis 连接的超时时间加上获取数据的实际工作量。我试图找到一些方法来做到这一点,但没有取得多大成功。
    猜你喜欢
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    • 2016-11-28
    • 1970-01-01
    • 2016-09-08
    • 2019-07-31
    • 2016-04-04
    • 1970-01-01
    相关资源
    最近更新 更多