社区要求我做一些实验,所以我做了它们。我发现我的问题的答案很简单:如果将它们放在同一方法之上@Cacheable
,@Async
则不要一起工作。
需要明确的是,我并不是在寻求一种直接使缓存返回 a 拥有的对象的方法CompletableFuture
。这是不可能的,如果不是这样,它将打破类异步计算的契约CompletableFuture
。
正如我所说,这两个注释不能在同一个方法上一起工作。如果你仔细想想,这很明显。标记@Async
也@Cacheable
意味着将整个缓存管理委托给不同的异步线程。如果值的计算CompletableFuture
需要很长时间才能完成,那么缓存中的值将在此时间之后由 Spring Proxy 放置。
显然,有一种解决方法。变通方法使用事实 the CompletableFuture
is a promise。让我们看一下下面的代码。
@Component
public class CachedService {
/* Dependecies resolution code */
private final AsyncService service;
@Cacheable(cacheNames = "ints")
public CompletableFuture<Integer> randomIntUsingSpringAsync() throws InterruptedException {
final CompletableFuture<Integer> promise = new CompletableFuture<>();
// Letting an asynchronous method to complete the promise in the future
service.performTask(promise);
// Returning the promise immediately
return promise;
}
}
@Component
public class AsyncService {
@Async
void performTask(CompletableFuture<Integer> promise) throws InterruptedException {
Thread.sleep(2000);
// Completing the promise asynchronously
promise.complete(random.nextInt(1000));
}
}
诀窍是创建一个不完整的承诺并立即从标有@Cacheable
注释的方法中返回它。Promise 将由另一个拥有该@Async
注解标记的方法的 bean 异步完成。
作为奖励,我还实现了一个不使用 Spring@Async
注解的解决方案,而是直接使用类中可用的工厂方法CompletableFuture
。
@Cacheable(cacheNames = "ints1")
public CompletableFuture<Integer> randomIntNativelyAsync() throws
InterruptedException {
return CompletableFuture.supplyAsync(this::getAsyncInteger, executor);
}
private Integer getAsyncInteger() {
logger.info("Entering performTask");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return random.nextInt(1000);
}
无论如何,我分享了我的 GitHub 问题spring-cacheable-async的完整解决方案。
最后,以上是对 Jira SPR-12967所指内容的详细说明。
我希望它有所帮助。干杯。