我正在使用jersey(JAX-RS)编写REST服务。基本上,它应该执行以下操作:
有一个包含很多key = value对的文本文件。 REST服务的用户应该能够查询密钥并接收值。
现在为每个查询加载和拆分整个文本文件需要太长时间。相反,我想将文本文件加载到Hashmap中并以固定的间隔重新加载。
我不知道如何实现此行为,以便Hashmap在查询之间存活,并且在重新加载数据时查询REST服务不会导致并发问题。
我应该怎么做才能拥有这样一个"缓存"在我的申请中?
答案 0 :(得分:1)
JAX-RS默认资源生命周期是按请求(请求范围),因此您需要将资源标记为@Singleton
,以使其在并发请求中共享。
@Singleton
javax.inject.Singleton
在此范围内,每个jax-rs应用程序只有一个实例。 Singleton资源可以使用@Singleton进行注释,并且可以使用Application实例注册其类。您还可以通过将单例实例注册到Application中来创建单例。
Life-cycle of Root Resource Classes
接下来,您需要实现定期刷新的线程安全缓存,以存储您的地图。
我通常会使用Guava CacheBuilder来执行此操作:
private final LoadingCache<Object,Map<String,String>> cache;
protected final Object CACHE_KEY = new Object();
//Create a Cache and keep it in the instance variable
public MyClass() {
this.cache = CacheBuilder.newBuilder()
.maximumSize(1)
.refreshAfterWrite(10,TimeUnit.MINUTES)
.build(new CacheLoader<Object,Map<String,String>>() {
@Override
public Map<String, String> load(Object key) {
//Parse your file and return a Map<String,String>
}
});
}
@GET
public void doIt() {
//Get a cached copy of your Map
Map<String,String> values = cache.get(CACHE_KEY);
}
缓存实例可以安全地在多个线程中使用(尽管您仍需要处理从缓存返回的对象的线程安全性),并且会在10分钟内自动刷新您的条目。
在一个更复杂的系统中,您可能还想在其他地方创建LoadingCache
实例,并将其注入资源类(在这种情况下,您可以将请求作为范围保留)。