Play 2允许您通过不会阻止该线程的AsyncResult执行async webservice calls:
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调用的结果直接传递给用户)时才有效。但是,如果您必须对结果执行其他操作,该怎么办?
看the documentation,好像你可以这样做:
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将执行传递给其他线程的同时进行异步调用?
答案 0 :(得分:1)
看看https://github.com/jroper/play-promise-presentation。对于我来说,如何设计一个可能有多个承诺调用等的系统,并将各种承诺响应操作到更复杂的响应所需的内容等等,这对我来说真的很清楚。
最好的部分是 - 这个例子并不太宽泛。它阅读得非常好,理解起来非常简单。
答案 1 :(得分:0)
好的,我找到了一个解决方案,虽然有点冗长。你能做的就是把所有东西都搬到一个演员身上。
在Global对象中设置Actor,但将ActorRef保存在您可以访问的位置。
ActorRef myActor = Akka.system().actorOf(new Props(MyActor.class));
在你的演员中,进行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
}
在你的控制器中,只需将调用包装在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
答案 2 :(得分:0)
不需要创建actor来推迟计算。
您可以使用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
返回Result
,您就可以了。
答案 3 :(得分: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()));
}
});