番石榴中的条件记忆
Conditional memoization in Guava
我知道如何memoize a single object。但是,我只想在满足某些条件时才记忆。我调用的服务有时 returns 响应不成功。我只想在服务响应成功时进行记忆。
MyResponse myResponse = myService.call()
boolean success = myResponse.isSuccessful();
我的缓存是这样创建的:
private Supplier<MyResponse> cache;
private void createCache() {
this.cache = Suppliers
.memoizeWithExpiration(myService::call, timeout,
TimeUnit.MINUTES);
}
问题: 是否可以仅在响应成功时使用传递给 memoizeWithExpiration
方法的供应商以某种方式缓存响应?
我发现这样做的唯一解决方法是,在检索值时,先调用 cache.get()
,检查缓存中存储的对象是否成功,如果不成功,则调用 createCache()
再次清除它,然后再次获取值。这样,如果后续服务调用 returns 一个有效对象,它将被存储,如果不是,每个后续调用都将清除缓存并再次调用该服务。
public MyResponse getResponse() {
MyResponse myResponse = cache.get();
if (myResponse.isSuccess()) {
return myResponse;
} else {
createCache();
return cache.get();
}
}
然而,在此解决方案中,如果缓存为空且服务 returns 未成功响应,则会立即再次调用。
您可以在服务 class 或任何其他合适的地方(这里我假设它在您的服务中)创建一个方法 callUntilSuccess
。您还可以在此方法中定义最大尝试次数,之后它将 return 为空,因此您可以避免无限期地调用您的服务(此建议未在下面提供的代码中实现,但它很容易这样做)。由于 Guava 方法需要 Supplier,您甚至可以使用此逻辑创建一个 lambda 并将其直接传递给 memoizeWithExpiration
方法。
public MyResponse callUntilSuccess() {
MyResponse response = myService.call();
while (!response.isSuccessful()) {
response = myService.call();
}
return response;
}
然后这样memoization:
private void createCache() {
this.cache = Suppliers
.memoizeWithExpiration(myService::callUntilSuccess, timeout,
TimeUnit.MINUTES);
}
这会是您要找的吗?
private void createCache() {
this.cache = Suppliers.memoizeWithExpiration(
Suppliers.compose(
response -> (response.isSuccess() ? response : null),
myService::call
),
timeout,
TimeUnit.MINUTES
);
}
这里,它会缓存响应,或者null,取决于它是否成功。
有关 compose
的更多信息,请点击此处 https://github.com/google/guava/blob/master/guava/src/com/google/common/base/Suppliers.java#L45
编辑:
如果您需要在成功时缓存值,并在失败时将缓存留空,同时 return 处理失败的请求,那么您自己就差不多了,只需稍微更改 return 中的逻辑 getResponse
,像这样:
public MyResponse getResponse() {
final MyResponse myResponse = cache.get();
if (!myResponse.isSuccess()) {
this.createCache(); // clear cache
}
return myResponse; // don't call .get() again!
}
我知道如何memoize a single object。但是,我只想在满足某些条件时才记忆。我调用的服务有时 returns 响应不成功。我只想在服务响应成功时进行记忆。
MyResponse myResponse = myService.call()
boolean success = myResponse.isSuccessful();
我的缓存是这样创建的:
private Supplier<MyResponse> cache;
private void createCache() {
this.cache = Suppliers
.memoizeWithExpiration(myService::call, timeout,
TimeUnit.MINUTES);
}
问题: 是否可以仅在响应成功时使用传递给 memoizeWithExpiration
方法的供应商以某种方式缓存响应?
我发现这样做的唯一解决方法是,在检索值时,先调用 cache.get()
,检查缓存中存储的对象是否成功,如果不成功,则调用 createCache()
再次清除它,然后再次获取值。这样,如果后续服务调用 returns 一个有效对象,它将被存储,如果不是,每个后续调用都将清除缓存并再次调用该服务。
public MyResponse getResponse() {
MyResponse myResponse = cache.get();
if (myResponse.isSuccess()) {
return myResponse;
} else {
createCache();
return cache.get();
}
}
然而,在此解决方案中,如果缓存为空且服务 returns 未成功响应,则会立即再次调用。
您可以在服务 class 或任何其他合适的地方(这里我假设它在您的服务中)创建一个方法 callUntilSuccess
。您还可以在此方法中定义最大尝试次数,之后它将 return 为空,因此您可以避免无限期地调用您的服务(此建议未在下面提供的代码中实现,但它很容易这样做)。由于 Guava 方法需要 Supplier,您甚至可以使用此逻辑创建一个 lambda 并将其直接传递给 memoizeWithExpiration
方法。
public MyResponse callUntilSuccess() {
MyResponse response = myService.call();
while (!response.isSuccessful()) {
response = myService.call();
}
return response;
}
然后这样memoization:
private void createCache() {
this.cache = Suppliers
.memoizeWithExpiration(myService::callUntilSuccess, timeout,
TimeUnit.MINUTES);
}
这会是您要找的吗?
private void createCache() {
this.cache = Suppliers.memoizeWithExpiration(
Suppliers.compose(
response -> (response.isSuccess() ? response : null),
myService::call
),
timeout,
TimeUnit.MINUTES
);
}
这里,它会缓存响应,或者null,取决于它是否成功。
有关 compose
的更多信息,请点击此处 https://github.com/google/guava/blob/master/guava/src/com/google/common/base/Suppliers.java#L45
编辑:
如果您需要在成功时缓存值,并在失败时将缓存留空,同时 return 处理失败的请求,那么您自己就差不多了,只需稍微更改 return 中的逻辑 getResponse
,像这样:
public MyResponse getResponse() {
final MyResponse myResponse = cache.get();
if (!myResponse.isSuccess()) {
this.createCache(); // clear cache
}
return myResponse; // don't call .get() again!
}