Java Spring@Cacheable和@Async注释
我需要缓存一些异步计算的结果。具体来说,为了克服这个问题,我尝试使用Spring4.3缓存和异步计算特性 作为一个示例,让我们以以下代码为例:Java Spring@Cacheable和@Async注释,java,spring,spring-cache,completable-future,spring-async,Java,Spring,Spring Cache,Completable Future,Spring Async,我需要缓存一些异步计算的结果。具体来说,为了克服这个问题,我尝试使用Spring4.3缓存和异步计算特性 作为一个示例,让我们以以下代码为例: @Service class AsyncService { @Async @Cacheable("users") CompletableFuture<User> findById(String usedId) { // Some code that retrieves the user relative
@Service
class AsyncService {
@Async
@Cacheable("users")
CompletableFuture<User> findById(String usedId) {
// Some code that retrieves the user relative to id userId
return CompletableFuture.completedFuture(user);
}
}
@服务
类异步服务{
@异步的
@可缓存(“用户”)
CompletableFuture findById(字符串usedId){
//某些代码检索相对于userId userId的用户
返回CompletableFuture.completedFuture(用户);
}
}
可能吗?我的意思是,Spring的缓存抽象能否正确处理CompletableFuture
类型的对象?我知道它有类似的功能,但如果配置正确,我无法理解Spring是否会使用它
编辑:我对
用户
对象本身不感兴趣,而是对表示计算的CompletableFuture
感兴趣。根据,ListenableFuture
(CompletableFuture
)不受支持。理论上,只要
背后的CacheManager实现不是序列化缓存对象(如Hazelcast支持的缓存)@Cacheable
- 由于
持有一种状态,可以通过调用CompletableFuture
方法来修改该状态,因此API的所有用户都不要乱动缓存的对象,这一点很重要。否则,cancel()
中的缓存对象可能无法再被检索,因此有必要进行缓存逐出未来
- 值得验证注释后面的代理的调用顺序。i、 e.
代理是否总是在@Cacheable
代理之前调用?还是反过来?还是视情况而定?例如,如果之前调用了@Async
,它将在@Async
中触发一个ForkJoinPool
,然后从缓存中检索另一个对象可调用的
- 社区要求我做一些实验,所以我做了。我发现我的问题的答案很简单:
@Cacheable
和@Async
如果放在同一个方法之上,它们就不能一起工作
明确地说,我并不是在寻求一种直接使缓存返回CompletableFuture所拥有的对象的方法。这是不可能的,如果不是这样,它将打破CompletableFuture
类异步计算的契约
正如我所说的,这两个注释在同一个方法上不起作用。如果你仔细想想,这是显而易见的。用@Async
标记也是@Cacheable
的意思是将整个缓存管理委托给不同的异步线程。如果CompletableFuture
值的计算需要很长时间才能完成,则Spring代理会将缓存中的值放置在该时间之后
显然,有一个解决办法。解决方案使用了这样一个事实:CompletableFuture
是一个承诺。让我们看看下面的代码
@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));
}
}
无论如何,我分享了我的GitHub问题的完整解决方案
最后,以上是对Jira所指内容的详细描述
我希望有帮助。
干杯。在一个类中的方法上添加@Async
注释,并在另一个类中的方法级别添加@Cacheable
注释
然后从服务或任何不同的层调用@Async
方法
Redis cache和Async对我来说都很有效,这大大提高了性能。我尝试了下面的方法,似乎很有效
- 使用
@cacable
创建一个方法,该方法执行实际的业务逻辑
- 使用
@Async
创建一个方法,该方法调用上述@Cachable
方法并返回一个CompletableFuture
- 在主执行流中使用
@Async
调用该方法
例如:
public class Main {
public void cachedAsyncData() {
try {
asyncFetcher.getData().get();
} catch(Exception e){}
}
}
public class AsyncFetcher {
@Async
public CompletableFuture<String> getData() {
return CompletableFuture.completedFuture(cacheFetcher.getData());
}
}
public class CacheFetcher {
@Cacheable
public String getData() {
return "DATA";
}
}
公共类主{
public void cachedAsyncData(){
试一试{
asyncFetcher.getData().get();
}捕获(例外e){}
}
}
公共类异步获取程序{
@异步的
公共CompletableFuture getData(){
返回CompletableFuture.completedFuture(cacheFetcher.getData());
}
}
公共类缓存获取程序{
@可缓存
公共字符串getData(){
返回“数据”;
}
}
感谢您的回复。在你链接的Jira中,有人问了一个不同的问题。据我所知,在Jira中,用户要求缓存ListenableFuture
的内部值。我认为只要CompletableFuture
遵守Object
的契约,它就可以成功缓存,不是吗?你试过了吗?我这几天不得不试一下@Kayaman,我会让你知道我的测试结果的。很好。我一直在等着看是否有人在这里接球。我自己在谷歌上搜索了一下,但只找到了@Async
任务中的未来与兼容未来
,这些任务在4.2
@Kayaman中得到了修复。我用我的结果给出了答案。希望有帮助。不,它不起作用。今天我做了一些实验。明天我会发布这些实验的结果。我投票支持你尝试,但你所做的看起来像是一个黑客。放弃Cacheable
注释,直接使用缓存管理器会更清晰。或者注册一个这样的回调。@Cacheable
注释下的机制非常有用。我使用的是Spring,所以我尝试按照它的理念来做事情。嗨@Rohit,欢迎来到Stack Overflow。据我所知,这类似于我们在项目中实施的解决方案。不过,我认为最好添加一些代码来说明您的解决方案,并在描述中更加具体。
public class Main {
public void cachedAsyncData() {
try {
asyncFetcher.getData().get();
} catch(Exception e){}
}
}
public class AsyncFetcher {
@Async
public CompletableFuture<String> getData() {
return CompletableFuture.completedFuture(cacheFetcher.getData());
}
}
public class CacheFetcher {
@Cacheable
public String getData() {
return "DATA";
}
}