[英]How to implement a Guava Cache with the value as number of hits?
我正在嘗試實現一個緩存,它將計算過去 5 分鍾內的登錄嘗試次數,在我的代碼中,我想檢查用戶是否嘗試了超過 MAX_ATTEMPTS。
在我在網上找到的“番石榴緩存”的所有代碼示例中,使用加載方法從其他來源獲取值或使用某種方法計算它,我如何在每次緩存命中時增加它?
static LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
.maximumSize(100000)
.expireAfterAccess(5, TimeUnit.MINUTES)
.build(
new CacheLoader<String, Integer>() {
public Integerload(String user) {
return ????;
}
}
);
稍后在運行時我想檢查:
if(cache.getIfPresent(user) != null && cache.get(user) > MAX_ATTEMPTS)
並在以下情況下增加它:
if(cache.getIfPresent(user) != null && cache.get(user) <= MAX_ATTEMPTS)
@Oren 您的解決方案不是線程安全的,因為您正在對 Cache 之外的值進行操作。 您最好使用Cache#asMap()
視圖並更改ConcurrentMap#compute(K, BiFunction<K, V, V>)
方法中的值:
forgetPasswordCache.asMap().compute(email, (cachedEmail, currentCount) -> {
if (currentCount != null && currentCount >= RESET_PASSWORD_MAX_ATTEMPTS) {
logger.error("User with id: " + user.getId() + " and email: " + email +
" has reached the maximum number of reset password attempts, the mail will not be sent");
return null;
}
if (currentCount == null) {
return 1;
} else {
return currentCount + 1;
}
});
您可以嘗試修改以下代碼段:
public class Demo {
public static void main(String[] x) {
CacheLoader<String, AtomicInteger> initialValueLoader = new CacheLoader<String, AtomicInteger>() {
@Override
public AtomicInteger load(String key) {
// do not care of the key. everybody starts with 0 login attempts.
return new AtomicInteger(0);
}
};
LoadingCache<String, AtomicInteger> c = CacheBuilder
.newBuilder()
.maximumSize(100000)
.expireAfterAccess(2, TimeUnit.SECONDS)
.build(initialValueLoader);
String user = "bob";
try {
// when the user tries to login, increment the attemps by one
Verify.verify(c.get(user).incrementAndGet() == 1);
// next call will get one
Verify.verify(c.get(user).get() == 1);
} catch (ExecutionException e) {
throw new RuntimeException("oups: " + e, e);
}
// simulate time
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
// after some time, the cache is cleared
try {
Verify.verify(c.get(user).get() == 0);
} catch (ExecutionException e) {
throw new RuntimeException("oups: " + e, e);
}
System.out.println("done.");
}
}
僅使用 Guava 的緩存功能解決(不使用加載器)
緩存看起來像這樣:
public class ForgetPasswordAttemptsCache {
private static final Cache<String, Integer> forgetPasswordCache = CacheBuilder.newBuilder()
.expireAfterAccess(24, TimeUnit.HOURS)
.build();
private ForgetPasswordAttemptsCache(){
}
public static Cache<String, Integer> getInstance() {
return forgetPasswordCache;
}
}
以及它的使用:
final String email = user.getEmail();
Integer currentCount = ForgetPasswordAttemptsCache.getInstance().getIfPresent(email);
if (currentCount != null && currentCount >= RESET_PASSWORD_MAX_ATTEMPTS) {
logger.error("User with id: " + user.getId() + " and email: " + email +
" has reached the maximum number of reset password attempts, the mail will not be sent");
return;
}
if (currentCount == null) {
ForgetPasswordAttemptsCache.getInstance().put(email, new Integer(1));
} else {
ForgetPasswordAttemptsCache.getInstance().put(email, new Integer(currentCount + 1));
}
感謝 spi 提供此解決方案。 (現在我正在尋找一種方法來測試它,而無需運行 24 小時的測試。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.