我正在使用球衣(JAX-RS)編寫REST服務。本質上,它應該執行以下操作:保留並更新REST服務中的數據(JAX-RS)
有一個包含大量鍵=值對的文本文件。 REST服務的用戶應該能夠查詢密鑰並接收該值。
現在,爲每個查詢加載和分割整個文本文件需要很長時間。相反,我想將文本文件加載到Hashmap中並以固定間隔重新加載它。
我不知道如何實現此行爲,以便Hashmap在查詢之間存活,並且在重新加載數據時查詢REST服務不會導致併發問題。
我該如何在我的應用程序中擁有這樣的「緩存」?
我正在使用球衣(JAX-RS)編寫REST服務。本質上,它應該執行以下操作:保留並更新REST服務中的數據(JAX-RS)
有一個包含大量鍵=值對的文本文件。 REST服務的用戶應該能夠查詢密鑰並接收該值。
現在,爲每個查詢加載和分割整個文本文件需要很長時間。相反,我想將文本文件加載到Hashmap中並以固定間隔重新加載它。
我不知道如何實現此行爲,以便Hashmap在查詢之間存活,並且在重新加載數據時查詢REST服務不會導致併發問題。
我該如何在我的應用程序中擁有這樣的「緩存」?
JAX-RS默認資源生命週期是按請求(請求範圍),因此您需要將資源標記爲@Singleton
,以使其在併發請求之間共享。
@Singleton
javax.inject.Singleton
在該範圍有每JAX-RS應用只有一個實例。 Singleton資源可以使用@Singleton註釋,並且它的類可以使用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
實例,並將其注入到資源類中(在這種情況下,您可以將其保留爲請求範圍)。