简体   繁体   English

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

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

I started working with CompletableFuture in Spring Boot, and I'm seeing in some places that the usual repository methods return CompletableFuture <Entity> instead of Entity . 我开始在Spring Boot中使用CompletableFuture ,在某些地方,我看到通常的存储库方法返回CompletableFuture <Entity>而不是Entity

I do not know what is happening, but when I return instances of CompletableFuture in repositories, the code runs perfectly. 我不知道发生了什么,但是当我在存储库中返回CompletableFuture实例时,代码可以完美运行。 However when I return entities, the code does not work asynchronously and always returns null . 但是,当我返回实体时,代码无法异步工作,并且始终返回null

Here is an example: 这是一个例子:

@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())
        );
    }
}

The previous code runs perfectly but the following code doesn't run asynchronously and the result is always null . 前面的代码可以完美运行,但是后面的代码不能异步运行,结果始终为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());
    }
}

Why doesn't this second code work? 为什么第二个代码不起作用?

As per the Spring @Async Javadoc : 根据Spring @Async Javadoc

the return type is constrained to either void or Future 返回类型被限制为voidFuture

and it is also further detailed in the reference documentation : 并且在参考文档中也有更详细的说明

In the simplest case, the annotation may be applied to a void -returning method. 在最简单的情况下,可以将注释应用于返回void方法。

[…] […]

Even methods that return a value can be invoked asynchronously. 即使返回值的方法也可以异步调用。 However, such methods are required to have a Future typed return value. 但是,要求此类方法具有Future类型的返回值。 This still provides the benefit of asynchronous execution so that the caller can perform other tasks prior to calling get() on that Future. 这仍然提供了异步执行的好处,以便调用者可以在该Future上调用get()之前执行其他任务。

In your second example, your @Async -annotated methods do not return a Future (or ListenableFuture and CompletableFuture which are also supported). 在第二个示例中, @Async方法不返回Future (或也支持的ListenableFutureCompletableFuture )。 However, Spring has to run your method asynchronously. 但是,Spring必须异步运行您的方法。 It can thus only behave as if your method had a void return type, and thus it returns null . 因此,它只能表现为您的方法具有void返回类型,并因此返回null

As a side note, when you use @Async , your method will already run asynchronously, so you shouldn't use CompletableFuture.supplyAsync() inside the method. 附带说明一下,当您使用@Async ,您的方法将已经异步运行,因此您不应在该方法内部使用CompletableFuture.supplyAsync() You should simply compute your result and return it, wrapped in CompletableFuture.completedFuture() if necessary. 您应该只计算结果并将其返回,并在必要时将其包装在CompletableFuture.completedFuture() 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. 如果您的方法仅是组成期货(例如,您的服务只是组成异步存储库结果),那么您可能不需要@Async批注。 See also the example from the Getting Started guide . 另请参阅《入门指南》中的示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM