gpt4 book ai didi

java - spring 缓存,TTL 除非服务关闭

转载 作者:太空宇宙 更新时间:2023-11-04 07:27:34 25 4
gpt4 key购买 nike

我有一个有趣的任务,我需要缓存我的方法的结果,这对于 spring 缓存抽象来说非常简单

@Cachable(...)
public String getValue(String key){
return restService.getValue(key);
}

restService.getValue() 的目标是 REST 服务,如果端点出现故障,该服务可以应答也可以不应答。

我需要为缓存值设置一个特定的 TTL,比如说 5 分钟,但如果服务器关闭,我需要返回最后一个值,即使它延长了 5 分钟。

我正在考虑使用第二个可缓存方法,它没有 TTL 并且始终返回最后一个值,如果restService 不返回任何内容,则会从 getValue 调用它,但也许有更好的方法?

最佳答案

我也对此感兴趣一段时间了。抱歉,我还没有找到任何简单的方法来做到这一点。 Spring不会为你做这件事,更多的问题是Spring包装的缓存实现是否可以做到这一点。我假设您正在使用 EhCache 实现。不幸的是,据我所知,这个功能并不是现成的。

根据您的问题,可以通过多种方式实现类似的目标

1) 使用永恒的缓存时间并有一个​​第二类线程,它定期循环刷新缓存的数据。我还没有完全做到这一点,但是 Thread 类需要看起来像这样:

@Autowired    
EhCacheCacheManager ehCacheCacheManager;
...
//in the infinite loop
List keys = ((Ehcache) ehCacheCacheManager.getCache("test").getNative Cache()).getKeys();
for (int i = 0; i < keys.size(); i++) {
Object o = keys.get(i);
Ehcache ehcache = (Ehcache)ehCacheCacheManager.getCache("test").getNativeCache()
Element item = (ehcache).get(o);

//get the data based on some info in the value, and if no exceptions
ehcache.put(new Element(element.getKey(), newValue));

}
  • 好处是这对于 @Cacheable 调用者来说非常快,缺点是您的服务器可能会获得比必要的更多的命中

2) 你可以做一个CacheListener来监听驱逐事件,临时存储数据。如果服务器调用失败,请使用该数据并从方法返回。

ehcache.xml

    <cacheEventListenerFactory class="caching.MyCacheEventListenerFactory"/>

</cache>
</ehcache>

工厂: 导入net.sf.ehcache.event.CacheEventListener; 导入net.sf.ehcache.event.CacheEventListenerFactory; 导入java.util.Properties;

public class MyCacheEventListenerFactory extends CacheEventListenerFactory {
@Override
public CacheEventListener createCacheEventListener(Properties properties) {
return new CacheListener();
}
}

伪实现 导入net.sf.ehcache.CacheException; 导入net.sf.ehcache.Ehcache; 导入net.sf.ehcache.Element; 导入net.sf.ehcache.event.CacheEventListener;

import java.util.concurrent.ConcurrentHashMap;

public class CacheListener implements CacheEventListener {
//prob bad practice to use a global static here - but its just for demo purposes
public static ConcurrentHashMap myMap = new ConcurrentHashMap();

@Override
public void notifyElementPut(Ehcache ehcache, Element element) throws CacheException {
//we can remove it since the put happens after a method return
myMap.remove(element.getKey());
}

@Override
public void notifyElementExpired(Ehcache ehcache, Element element) {
//expired item, we should store this
myMap.put(element.getKey(), element.getValue());
}
//....
}
  • 这里的一个挑战是 key 不是很有用,您可能需要在返回值中存储有关 key 的某些内容,以便在服务器调用失败时能够获取它。这感觉有点老套,我还不确定这是否完全是防弹的。它可能需要一些测试。

3)付出了很多努力,但很有效:

@Cacheable("test")
public MyObject getValue(String data) {
try {
MyObject result = callServer(data);
storeResultSomewhereLikeADatabase(result);
} catch (Exception ex) {
return getStoredResult(data);
}
}

这里的优点是它可以在服务器重新启动之间工作,并且您可以简单地扩展它以允许集群服务器之间共享缓存。我有一个 12 集群环境中的版本,每个集群首先检查数据库,看看是否有任何其他集群首先获得了“昂贵”的数据然后重用它而不是进行服务器调用。

还有一个细微的变体,即使用第二个 @Cacheable 方法和 @CachePut 而不是 DB 来存储数据。但这意味着内存使用量会增加一倍。根据您的结果大小,这可能是可以接受的。

关于java - spring 缓存,TTL 除非服务关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18281595/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com