当前位置: 首页 > 面试题库 >

Play Framework 2.5 JavaAsync引发CompletionException

毕泽宇
2023-03-14
问题内容

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

@Singleton
public class AbstractSource {

    public Source<ByteString, ?> getChunked(String html) {

        return Source.<ByteString>actorRef(256, OverflowStrategy.dropNew())
                .mapMaterializedValue(sourceActor -> {
                    sourceActor.tell(ByteString.fromString(html), null);
                    sourceActor.tell(new Status.Success(NotUsed.getInstance()), null);
                    return null;
                });

    }

}

这是我的控制器:

@Singleton
@AddCSRFToken
public class Application extends Controller {

    @Inject
    private AbstractSource abstractSource;

    public CompletionStage<Result> index() {


        CompletionStage<Source<ByteString, ?>> source = CompletableFuture.supplyAsync(() -> 
                                                  abstractSource.getChunked(index.render(CSRF.getToken(request()).map(t -> 
                                                    t.value()).orElse("no token")).body()
                                                   )
                                                );

        return source.thenApply( chunks -> ok().chunked(chunks));

    }

}

现在,当我运行该应用程序时,它会引发以下异常:

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[CompletionException: java.lang.RuntimeException: There is no HTTP Context available from here.]]
    at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:269)
    at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:195)
    at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
    at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
    at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:98)
    at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:99)
    at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:98)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:344)
    at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:343)
    at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
Caused by: java.util.concurrent.CompletionException: java.lang.RuntimeException: There is no HTTP Context available from here.
    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1592)
    at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.lang.RuntimeException: There is no HTTP Context available from here.
    at play.mvc.Http$Context.current(Http.java:57)
    at play.mvc.Controller.request(Controller.java:36)
    at com.mabsisa.ui.web.controllers.Application.lambda$index$1(Application.java:31)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
    ... 5 common frames omitted

我没有在任何地方使用HTTP上下文,所以为什么我没有得到为什么。当返回带有分块响应的正常Result时,相同的代码正在工作。请帮忙


问题答案:

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

但是,切换线程时您可能会丢失此信息,这就是您遇到问题的原因。您 可能 认为您没有访问HTTP上下文,但实际上您在访问-您正在使用request()

因此,您必须更改代码以supplyAsync与执行程序一起使用:

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#supplyAsync-
java.util.function.Supplier-
java.util.concurrent.Executor-

由此:

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;



 类似资料:
  • 问题内容: 我只想从mongodb信息中处理对象,但是当我执行此方法时,要使一些对象成为对象,但总是返回该错误java.util.NoSuchElementException。 问题答案: 可能的问题是,您在一个循环中调用了3次方法。您应该调用一次并将其结果存储在变量中,因为它会检索迭代中的下一个元素

  • 问题内容: 我正在尝试使用IntelliJ 12.1.3使用JPA测试Hibernate 4.2.1.Final,但出现以下错误。 一切似乎都设置正确(我让IntelliJ生成了映射),由于我对Hibernate和JPA的经验为零,所以我无所适从。 为什么要启用NPE? 主类: 错误: Persistance.xml 问题答案: 该消息向我表明它无法连接到数据库。仔细检查您的连接字符串,并确保您的

  • 我正在使用gson将json字符串转换为Java对象。result2的值与Result1的值完全相同。(从调试器复制;添加反斜杠) 转换Result1:com.google.gson.JsonSyntaxException时引发以下异常:com.google.gson.stream.MalFormedJsonException:第1行第170列需要EOF 转换result2工作良好。 json字符

  • 好吧,所以我显然不太理解doReturn(...)。when(...)当(...).Thenreturn(...).

  • 我需要创建自己的UnaryTransformer实例,该实例接受类型为Array[String]的Dataframe列,并且还应该输出相同的类型。在尝试这样做时,我在Spark版本2.1.0上遇到了ClassCastException。我做了一个样本测试来证明我的情况。 附加堆栈跟踪以供参考

  • 我的目标是向已创建的现有表中添加一个新行。但是,我得到以下错误。 输入学号:1234567 输入名字:Hello 输入姓氏:World 增加的价值 com.mysql.jdbc.exceptions.jdbc4.mysqlsyntaxerrorexception... 我明白这可能是一个非常愚蠢的问题,但我刚刚开始使用数据库,即使在查看了这里发布的大多数类似问题后,也无法找出代码哪里有问题。

  • 在我的Spring应用程序中,我使用StandardPasswordEncoder对用户密码进行编码。 我将用户数据保存在嵌入式H2数据库中。

  • 基本 版本控制 Git 分支(Branch) 本项目只使用一个分支,即 master。所有更改全部提交进 master,并确保 master 在任一时刻都是可编译可使用的。 发布(Release) 尽量使用自动化工具发布,比如 v2ray-core 使用 Travis-ci 作为自动编译和发布工具。 引用其它项目 Golang 产品代码只能使用 golang 的标准库,即名称不包含任何网址的包;