Lagomを試してみるシリーズ第7回です。今回はサービスから別サービスの呼び出しを試してみました。少しずつリアクティブっぽい感じになってきましたね。
別のサービスを呼び出すのは簡単で、以下のようにサービスのインターフェースをDIするだけで呼び出すことができます。呼び出した結果に対して処理を行う場合はthenApply
などで次の処理を合成します。ScalaでFuture
を扱ったことがある方であれば、Future
に対するmap
みたいなものだと思えばよいかと思います。CompletionStage
にはこの他にも合成用の様々なメソッドが用意されています。
public class MyServiceImpl implements MyService { private final HelloService helloService; @Inject public MyServiceImpl(HelloService helloService){ this.helloService = helloService; } @Override public ServiceCall<NotUsed, NotUsed, String> hoge() { return (id, msg) -> { CompletionStage<HelloResponse> f = helloService.hello().invoke(HelloRequest.of("Japan", "Naoki")); return f.thenApply(res -> res.message() + "!"); }; } }
クライアントのインターフェースをDIするだけでサービスを呼び出せるということはバイトコード生成的なことをやってるんだろうと思ったらjava.lang.reflect.Proxy
が使われているようです。
他のサーバで動いているサービスの呼び出しはどうやればいいんだろう?このあたりはLagomの肝の1つだと思うので、もっと複雑なケースや背後の仕組みも含めてもう少し詳しく調べてみたいところです。
また、Lagomのドキュメントによると、別サービスを呼び出すのではなく、以下のようにServiceCall
自体を合成することもできるみたいです。
public <Id, Request, Response> ServerServiceCall<Id, Request, Response> logged( ServerServiceCall<Id, Request, Response> serviceCall) { return HeaderServiceCall.compose(requestHeader -> { System.out.println("Received " + requestHeader.method() + " " + requestHeader.uri()); return serviceCall; }); } public ServerServiceCall<NotUsed, String, String> sayHello() { return logged( (id, name) -> completedFuture("Hello " + name) ); }
認証やログなどの共通的な処理はこんな感じで実装するとよさそうです。