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

时间:2018-04-30 13:58:53

标签: java return completable-future spring-async

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

我不知道发生了什么,但是当我在存储库中返回CompletableFuture的实例时,代码运行完美。但是,当我返回实体时,代码不会异步工作并始终返回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());
    }
}

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

1 个答案:

答案 0 :(得分:1)

根据the Spring @Async Javadoc

  

返回类型约束为voidFuture

它也是further detailed in the reference documentation

  

在最简单的情况下,注释可以应用于void - 返回方法。

     

[...]

     

即使是返回值的方法也可以异步调用。但是,此类方法需要具有Future类型的返回值。这仍然提供了异步执行的好处,以便调用者可以在调用Future上的get()之前执行其他任务。

在您的第二个示例中,您的@Async - 带注释的方法不会返回Future(或ListenableFutureCompletableFuture,这些方法也受支持)。但是,Spring必须异步运行您的方法。因此,它只能表现为您的方法具有void返回类型,因此它返回null

作为旁注,当您使用@Async时,您的方法已经异步运行,因此您不应在方法中使用CompletableFuture.supplyAsync()。您应该只计算结果并将其返回,必要时包含在CompletableFuture.completedFuture()中。如果您的方法只是组成future(就像您的服务只是组成异步存储库结果),那么您可能不需要@Async注释。另请参阅the example from the Getting Started guide