Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Play Framework 2.5 JavaAsync引发CompletionException_Java_Playframework_Playframework 2.0_Sbt - Fatal编程技术网

Play Framework 2.5 JavaAsync引发CompletionException

Play Framework 2.5 JavaAsync引发CompletionException,java,playframework,playframework-2.0,sbt,Java,Playframework,Playframework 2.0,Sbt,我正在使用Play2.5构建一个简单的应用程序。为了获得更好的性能,我将Akka分块响应与Java8 CompletionStage策略结合使用。下面是生成分块响应的代码(不使用ComperableFuture时工作正常): 我没有在任何地方使用HTTP上下文,所以我不明白为什么这不起作用。使用分块响应返回正常结果时,同样的代码也在工作。请对此提供帮助在处理CompletableFuture/CompletionStage时,您必须提供HTTP执行上下文。在Scala中,上下文信息是通过隐式传递

我正在使用Play2.5构建一个简单的应用程序。为了获得更好的性能,我将Akka分块响应与Java8 CompletionStage策略结合使用。下面是生成分块响应的代码(不使用ComperableFuture时工作正常):

我没有在任何地方使用HTTP上下文,所以我不明白为什么这不起作用。使用分块响应返回正常结果时,同样的代码也在工作。请对此提供帮助

在处理
CompletableFuture
/
CompletionStage
时,您必须提供HTTP执行上下文。在Scala中,上下文信息是通过隐式传递的,Java中不提供这些信息-这就是Play使用
ThreadLocal
的原因

但是,在切换线程时可能会丢失这些信息,这就是问题的原因。您可能认为您不访问HTTP上下文,但实际上您访问了—您使用的是
request()

因此,您必须更改代码,以便与执行器一起使用
supplyAsync

由此:

CompletableFuture.supplyAsync(() -> abstractSource.getChunked(index.render(CSRF.getToken(request()).map(t -> 
                                                    t.value()).orElse("no token")).body()
                                                   )
                                                );
为此:

CompletableFuture.supplyAsync(() -> abstractSource.getChunked(index.render(CSRF.getToken(request()).map(t -> 
                                                    t.value()).orElse("no token")).body()
                                                   )
                                                , ec.current());

其中,
ec
是您的上下文:
@Inject-HttpExecutionContext-ec

我对安东的回答进行了补充

如果您正在使用Play Java API构建一个非阻塞应用程序,每次需要调用
CompletionStage
上的方法时,注入
HttpExecutionContext
并传递
ec.current())
可能会变得相当麻烦

为了简化工作,您可以使用decorator,它将保留调用之间的上下文

public class ContextPreservingCompletionStage<T> implements CompletionStage<T> {

    private HttpExecutionContext context;
    private CompletionStage<T> delegate;

    public ContextPreservingCompletionStage(CompletionStage<T> delegate,
                                            HttpExecutionContext context) {
        this.delegate = delegate;
        this.context = context;
    }
    ...
}
如果您正在构建多层应用程序,并在不同的类之间传递
CompletionStage
s,那么这一点尤其有用


完整的decorator实现示例。

a一些答案有很好的解释……还有一件事想问一下,这是否是一种很好的设计方法?cn请分享您的观点?返回一个
CompletionStage
是在Play 2.5中定义异步操作的事实标准,所以您在这里很好。关于游戏中的分块响应:看一看——通过使用Akka streams,您已经走上了一条很好的道路,所以这里也不用担心——您的设计方法很好!很高兴我能帮忙!这是归档的,这里有文档,这是一个很好的答案,但如果我正确理解您将默认播放执行器传递给CompletableFuture,这将导致阻止请求执行器,如果您在异步中执行繁重的任务
CompletableFuture.supplyAsync(() -> abstractSource.getChunked(index.render(CSRF.getToken(request()).map(t -> 
                                                    t.value()).orElse("no token")).body()
                                                   )
                                                );
CompletableFuture.supplyAsync(() -> abstractSource.getChunked(index.render(CSRF.getToken(request()).map(t -> 
                                                    t.value()).orElse("no token")).body()
                                                   )
                                                , ec.current());
public class ContextPreservingCompletionStage<T> implements CompletionStage<T> {

    private HttpExecutionContext context;
    private CompletionStage<T> delegate;

    public ContextPreservingCompletionStage(CompletionStage<T> delegate,
                                            HttpExecutionContext context) {
        this.delegate = delegate;
        this.context = context;
    }
    ...
}
return new ContextPreservingCompletionStage<>(someCompletableFuture, context)
                            .thenCompose(something -> {...});
                            .thenApply(something -> {...});
return someCompletableFuture.thenComposeAsync(something -> {...}, context.current())
                            .thenApplyAsync(something -> {...}, context.current());