4

Play 2 允许您通过 AsyncResult 进行异步 Web 服务调用,这不会阻塞线程:

public static Result feedTitle(String feedUrl) {
    return async(
        WS.url(feedUrl).get().map(
            new Function<WS.Response, Result>() {
                public Result apply(WS.Response response) {
                    return ok("Feed title:" + response.asJson().findPath("title"));
                }
            }
        )
    );
}

这仅在您执行简单的事情(例如将 WS 调用的结果直接传递给用户)时才有效。但是,如果您必须对结果进行额外的操作怎么办?

查看文档,您似乎可以这样做:

Promise<Response> promise = WS.url("http://some.website.com").get();
Response response = promise.get();    // I've got the result, but I've also blocked

这显然是不理想的。有没有办法在允许 Play 将执行传递给其他线程的同时进行异步调用?

4

4 回答 4

1

看看https://github.com/jroper/play-promise-presentation。这真的让我明白了如何设计一个可以有多个 Promise 调用等的系统,并将各种 Promise 响应操作为更复杂的响应所需的响应等。

最好的部分是——这个例子感觉不太冗长。它读起来很好,很容易理解。

于 2012-09-07T15:02:25.203 回答
0

没有必要仅仅为了推迟计算而创建参与者。Promise.map(Function<A, B>)您可以使用和将后处理绑定到异步调用Promise.flatMap(Function<<A>, Promise<B>>)。这些调用是可链接的。

例子:

return async(WS.url("http://someservice.com/").get().map(
        new F.Function<play.libs.WS.Response, SomeData>() {
            @Override
            public SomeData apply (play.libs.WS.Response response) throws Throwable {
                SomeData someData = computeData(response);
                // Do extra computing here
                return someData;
            }
        }).map(
        new F.Function<SomeData, Result>() {
            @Override
            public Result apply(SomeData someData) throws Throwable {
                Result result = doSomethingElse(someData);
                return ok(result); 
            }
        })
 );

只要最后一个map返回 a Result,你就可以走了。

于 2013-11-04T18:34:20.163 回答
0

好的,我找到了一个解决方案,尽管有点冗长。你可以做的就是把所有东西都移到一个 Actor 上。

在全局对象中设置您的 Actor,但将 ActorRef 保存在您可以访问的位置。

ActorRef myActor = Akka.system().actorOf(new Props(MyActor.class));

在您的 Actor 中,执行 WS 调用。

public void onReceive(Object message) {
    WSRequestHolder request = WS.url("http://example.com");
    Response response = request.get().get();
    SomeResult result = doFurtherProcessing(response);
    getContext().sender().tell(result);    // reply the asking thread
}

在您的控制器中,只需将对 Actor 的调用包装在 async() 中

public static Result method() {
    String message = "hello";
    return async(
        Akka.asPromise(ask(myActor, message, 1000)).map(new Function<Object, Result>() {
            public Result apply(Object result) throws Throwable {
                return ok(result);
            }
        })
    );
}

参考:http ://www.playframework.org/documentation/2.0.3/JavaAkka

于 2012-08-31T05:48:12.003 回答
0

play2的替代答案

String url1 = String.format( "http://localhost:8080/site1", langcode );
String url2 = String.format( "http://localhost:8080/site2", langcode );
String url3 = String.format( "http://localhost:8080/site3", langcode );

F.Promise<WS.Response> remoteCall1 = WS.url(url1).get();
F.Promise<WS.Response> remoteCall2 = WS.url(url2).get();
F.Promise<WS.Response> remoteCall3 = WS.url(url3).get();

F.Promise<java.util.List<WS.Response>> promisesSequence = F.Promise.sequence(remoteCall1, remoteCall2, remoteCall3);

F.Promise<Result> resultPromise = promisesSequence.map(
    new Function<java.util.List<WS.Response>, Result>(){
        @Override
        public Result apply(java.util.List<WS.Response> responses){
            final StringBuffer sb = new StringBuffer();
            for(WS.Response r : responses){
                sb.append(r.getBody());
            }
            return ok( main.render("Output", sb.toString()));
        }
    });
于 2014-02-04T23:46:21.623 回答