I have some code that saves an entity to a database using spring-data
and then performs some other work foo()
and bar()
that needs the id
from the entity that has been saved. It looks like this:
private CompletableFuture<Void> save(MyEntity me) {
CompletableFuture<Void> future = ContextAwareCompletableFuture
.runAsync(() -> repository.save(me))
.thenRunAsync(() -> foo(me))
.thenRunAsync(() -> bar(me));
return future;
}
private Foo foo(MyEntitiy me) {
// Use the identifier for me to update some foo in another world
}
private Bar bar(MyEntitiy me) {
// Use the identifier for me to update some bar in at another time
}
Now, I do not want to return void
from my save
method. I want to return a MyEntity
so I tried:
private CompletableFuture<MyEntity> save(MyEntity me) {
CompletableFuture<MyEntity> future = ContextAwareCompletableFuture
.runAsync(() -> repository.save(me))
.thenRunAsync(() -> foo(me))
.thenRunAsync(() -> bar(me));
return future;
}
This does not work since runAsync
returns void. My method repository.save()
returns the object I wish to return but that call is at the beginning of the chain. I need to save the object before I can do my foo
and bar
.
So next thing I tried is:
private CompletableFuture<MyEntity> save(MyEntity me) {
CompletableFuture<MyEntity> future = ContextAwareCompletableFuture
.supplyAsync(() -> repository.save(me))
.thenApplyAsync((e) -> baz(e);
return future;
}
private MyEntity baz(MyEntitiy me) {
foo(me);
bar(me);
return me;
}
Now, that seems wrong to me. Foo
and Bar
will now have to be executed during the same stage and they might take some time.
How can I return the object saved in repository.save()
after foo
and bar
has finished properly?
If foo
and bar
may run concurrently, you may choose to chain on save
instead of sequencing them:
private CompletableFuture<MyEntity> save(MyEntity me) {
CompletableFuture<MyEntity> future = ContextAwareCompletableFuture
.supplyAsync(() -> repository.save(me));
CompletableFuture<Void> fooFuture = future
.thenAcceptAsync((e) -> foo(e));
CompletableFuture<Void> barFuture = future
.thenAcceptAsync((e) -> bar(e));
return future
.thenCombine(fooFuture, (result, fooResult) -> result)
.thenCombine(barFuture, (result, barResult) -> result);
}
Note I used thenAcceptAsync
instead of thenRunAsync
to avoid capturing me
. I avoided the capture in the end as well.
We can avoid one thenCombine
if we return the entity on fooFuture
and barFuture
:
private CompletableFuture<MyEntity> save(MyEntity me) {
CompletableFuture<MyEntity> future = ContextAwareCompletableFuture
.supplyAsync(() -> repository.save(me));
CompletableFuture<MyEntity> fooFuture = future
.thenApplyAsync((e) -> { foo(e); return e; });
CompletableFuture<MyEntity> barFuture = future
.thenApplyAsync((e) -> { bar(e); return e; });
return fooFuture
.thenCombine(barFuture, (fooResult, barResult) -> fooResult);
}
您可以使用一个可以填充并返回输入的方法进行链接:
.thenApply(e -> { foo(e); return e; }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.