coo*_*ude 13 spring-mvc redis spring-cache
我们有休息api申请.我们使用redis进行API响应缓存和内部方法缓存.如果是redis连接,那么它会使我们的API失效.我们想绕过redis缓存,如果redis连接失败或任何异常,而不是让我们的API失效.有一个接口CacheErrorHandler,但它处理redis get set操作失败而不是redis连接问题.我们使用的是Spring 4.1.2.
Joh*_*lum 11
让我们稍微熬一下吧.您的应用程序使用缓存(使用Redis实现).如果Redis连接是陈旧/关闭或其他,那么您希望应用程序绕过缓存并且(可能)直接转到底层数据存储(例如RDBMS).应用程序服务逻辑可能看起来类似于......
@Service
class CustomerService ... {
@Autowired
private CustomerRepository customerRepo;
protected CustomerRepository getCustomerRepo() {
Assert.notNull(customerRepo, "The CustomerRepository was not initialized!");
return customerRepo;
}
@Cacheable(value = "Customers")
public Customer getCustomer(Long customerId) {
return getCustomerRepo().load(customerId);
}
...
}
Run Code Online (Sandbox Code Playgroud)
Spring核心的缓存抽象中确定缓存"未命中"的所有重要因素是返回的值为null.因此,Spring Caching Infrastructure将继续调用实际的Service方法(即getCustomer).请记住,在返回getCustomerRepo().load(customerId)调用时,您还需要处理Spring的缓存基础结构现在尝试缓存该值的情况.
本着保持简单的精神,我们将不使用AOP,但您也应该能够使用AOP(您的选择)实现这一目标.
您(应该)需要的是一个"自定义"RedisCacheManager扩展SDR CacheManager实现,类似于......
package example;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCacheManager;
...
class MyCustomRedisCacheManager extends RedisCacheManager {
public MyCustomerRedisCacheManager(RedisTemplate redisTemplate) {
super(redisTemplate);
}
@Override
public Cache getCache(String name) {
return new RedisCacheWrapper(super.getCache(name));
}
protected static class RedisCacheWrapper implements Cache {
private final Cache delegate;
public RedisCacheWrapper(Cache redisCache) {
Assert.notNull(redisCache, "'delegate' must not be null");
this.delegate = redisCache;
}
@Override
public Cache.ValueWrapper get(Object key) {
try {
delegate.get(key);
}
catch (Exception e) {
return handleErrors(e);
}
}
@Override
public void put(Object key, Object value) {
try {
delegate.put(key, value);
}
catch (Exception e) {
handleErrors(e);
}
}
// implement clear(), evict(key), get(key, type), getName(), getNativeCache(), putIfAbsent(key, value) accordingly (delegating to the delegate).
protected <T> T handleErrors(Exception e) throws Exception {
if (e instanceof <some RedisConnection Exception type>) {
// log the connection problem
return null;
}
else if (<something different>) { // act appropriately }
...
else {
throw e;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
因此,如果Redis不可用,您可以做的最好的事情就是记录问题并继续让Service调用发生.显然,这会妨碍性能,但至少会提高人们对问题的认识.显然,这可以绑定到一个更强大的通知系统,但它是可能性的一个粗略的例子.重要的是,您的服务仍然可用,而应用程序服务所依赖的其他服务(例如Redis)可能已失败.
在这个实现中(与我之前的解释相比),我选择委托给底层的,实际的RedisCache实现让异常发生,然后完全了解Redis存在的问题,以便你可以适当地处理异常.但是,如果您确定Exception与检查时的连接问题有关,则可以返回"null"以使Spring Caching Infrastructure继续运行,就好像它是Cache"miss"(即Redis Connection = = Cache miss,在这种情况下).
我知道这样的事情可以帮助你解决问题,因为我为GemFire和Pivotal的客户之一构建了一个类似的"自定义"CacheManager实现原型.在那个特定的UC中,Cache"miss"必须由应用程序域对象的"过时版本"触发,其中生产中混合了通过Spring的缓存抽象连接到GemFire的新旧应用程序客户端.例如,应用程序域对象字段将在应用程序的较新版本中更改.
无论如何,希望这有助于或给你更多的想法.
干杯!
因此,我今天在挖掘核心Spring Framework Caching Abstraction源,解决了另一个问题,看来如果CacheErrorHandler正确实现,那么可能有问题的Redis Connection仍可能导致所需的行为,例如,高速缓存“未命中”(触发了返回空值)。
有关更多详细信息,请参见AbstractCacheInvoker源。
本cache.get(key)
应导致异常因故障Redis的连接,因此异常处理程序将被调用...
catch (RuntimeException e) {
getErrorHandler().handleCacheGetError(e, cache, key);
return null; // If the exception is handled, return a cache miss
}
Run Code Online (Sandbox Code Playgroud)
如果CacheErrorHandler正确处理了Cache“ get”错误(并且未重新引发/异常),则将返回空值,指示Cache“未命中”。
所有核心Spring Framework Cache 抽象注释(例如 @Cacheable)以及核心 SF 支持的 JSR-107 JCache 注释委托给底层的CacheManager,对于 Redis,即RedisCacheManager。
您可以在类似于此处的 Spring XML 配置元数据中配置 RedisCacheManager。
一种方法是为使用RedisConnection的 (Redis)CacheManager 编写 AOP 代理(间接从RedisTemplate来确定每个 (Redis)CacheManger 操作上的连接状态。
如果连接失败或关闭,对于标准缓存操作,(Redis)CacheManager 可以为getCache(String name)返回一个RedisCache实例,该实例始终返回 null(指示条目上的缓存未命中),从而传递到底层数据存储。
也许有更好的方法来处理这个问题,因为我不是所有 Redis(或 SDR)方面的专家,但这应该可行,并且可能会给您一些自己的想法。
干杯。
归档时间: |
|
查看次数: |
8527 次 |
最近记录: |