从存储库返回实体时如何使用 CompletableFuture.thenCompose()?

How to use CompletableFuture.thenCompose() when returning entities from repositories?

我开始在 Spring Boot 中使用 CompletableFuture,我在某些地方看到通常的存储库方法 return CompletableFuture <Entity> 而不是 Entity.

我不知道发生了什么,但是当我在存储库中 return 个 CompletableFuture 实例时,代码 运行 完美无缺。但是,当我 return 实体时,代码不会异步工作并且总是 returns null.

这是一个例子:

@Service
public class AsyncServiceImpl{
    /** .. Init repository instances .. **/

    @Async(AsyncConfiguration.TASK_EXECUTOR_SERVICE)
    public CompletableFuture<Token> getTokenByUser(Credential credential) {
        return userRepository.getUser(credential)
            .thenCompose(s -> TokenRepository.getToken(s));
    }
}

@Repository
public class UserRepository {

    @Async(AsyncConfiguration.TASK_EXECUTOR_REPOSITORY)
    public CompletableFuture<User> getUser(Credential credentials) {
        return CompletableFuture.supplyAsync(() -> 
            new User(credentials.getUsername())
        );
    }       
}

@Repository
public class TokenRepository {

    @Async(AsyncConfiguration.TASK_EXECUTOR_REPOSITORY)
    public CompletableFuture<Token> getToken(User user) {
        return CompletableFuture.supplyAsync(() -> 
            new Token(user.getUserId())
        );
    }
}

前面的代码 运行 很完美,但下面的代码不是 运行 异步的,结果总是 null.

@Service
public class AsyncServiceImpl {
    /** .. Init repository instances .. **/

    @Async(AsyncConfiguration.TASK_EXECUTOR_SERVICE)
    public CompletableFuture<Token> requestToken(Credential credential) {
        return CompletableFuture.supplyAsync(() -> userRepository.getUser(credential))
            .thenCompose(s -> 
                CompletableFuture.supplyAsync(() -> TokenRepository.getToken(s)));
    }
}

@Repository
public class UserRepository {
    @Async(AsyncConfiguration.TASK_EXECUTOR_REPOSITORY)
    public User getUser(Credential credentials) {
        return new User(credentials.getUsername());
    }       
}

@Repository
public class TokenRepository {
    @Async(AsyncConfiguration.TASK_EXECUTOR_SERVICE)
    public Token getToken(User user) {
        return new Token(user.getUserId());
    }
}

为什么第二个代码不起作用?

根据the Spring @Async Javadoc

the return type is constrained to either void or Future

也是further detailed in the reference documentation:

In the simplest case, the annotation may be applied to a void-returning method.

[…]

Even methods that return a value can be invoked asynchronously. However, such methods are required to have a Future typed return value. This still provides the benefit of asynchronous execution so that the caller can perform other tasks prior to calling get() on that Future.

在您的第二个示例中,您的 @Async 注释方法不 return 和 Future(或 ListenableFutureCompletableFuture 也受支持) .但是,Spring 必须异步地 运行 您的方法。因此它只能表现得好像你的方法有一个 void return 类型,因此它 returns null.

附带说明一下,当您使用 @Async 时,您的方法已经 运行 异步,因此您不应在方法内部使用 CompletableFuture.supplyAsync()。你应该简单地计算你的结果和 return 它,包裹在 CompletableFuture.completedFuture() if necessary. If your method is only composing futures (like your service that simply composes asynchronous repository results), then you probably don't need the @Async annotation. See also the example from the Getting Started guide.