PlayFramework2.5がリリースされました。
変更点について自分用に訳してみました。
https://www.playframework.com/documentation/2.5.x/Highlights25
英語はあまり得意ではないので、訳が怪しい箇所は原文をご覧ください。
Akka StreamsによるストリーミングAPI
Play2.5のメインテーマはIterateeベースの非同期IOのAPIをAkka Streamsに移行することでした。本来、ネットワーク越しにコミュニケーションがとったり、ファイルシステムのデータを読み書きしたりすることは
入出力データの流れが若干複雑になります。
多くの場合、このデータの流れは低レイヤーで行われ、フレームワークは具体的な値をイン・メモリのメッセージとして
アプリケーションに提供します。Playの振る舞いは多くの場合、ボディパーサがリクエストデータをJSONオブジェクトのようなオブジェクトに変換し、それをアプリケーションが使用し、JSONオブジェクトの結果データはPlayが元の形式のデータに戻します。
JVMでは、伝統的に入出力データはブロッキングな入力用ストリームAPIと出力用ストリームAPIを使用してきました。
これらのAPIは専用のスレッドを必要とします。読み込み時には、スレッドはデータをブロックして待たなければならず、
書き込み時には、スレッドは書き込み(フラッシュ)を行うためにデータをブロックして待たなければなりません。
Playのような非同期フレームワークには、上述したようなブロッキングなAPIを使用せずにリソースを制限することに多くの利点があります。
入出力データに対しては、代わりに非同期APIが使用される必要があり、フレームワークは、スレッドがブロックされている間待つのではなく、これらのデータの読み書きの完了の通知を受けるのです。
Play2.5より前は、Playは非同期入出力のメカニズムとしてIterateeを使用していましたが、Play2.5ではAkka Stramsを使用しています。
なぜIterateeではないのか?
Iterateeは非同期な入出力データに対する関数的なアプローチです。Iterateeは、非常に小さなAPIを提供する限りは非常に強力です。(※文中に『surface area』とあるが、これは何?) IterateeはAPIはfoldメソッドのみで成り立っており、残りのメソッドはこのメソッドを前提に実装されたヘルパーメソッドです。Iterateeはまた、コードがコンパイルされてしまえば、コードに並列化やエラーハンドリングのようなIterateeの実装に関連するバグが存在することはほぼないという、とても高度な安全性を提供します。多くのバグはIteratee内のビジネスロジックに存在するでしょう。この安全性と簡潔さは素晴らしいですが、一方で、その習熟曲線は急です。Iterateeを使用するプログラミングは、伝統的なIOハンドリングからの発想の転換を必要とします。そして、多くの開発者は、その発想の転換に必要な投資が、IO処理に必要なことに対してとても高いものであると判断します。
もう一つのIterateeの欠点は、それらが高度な関数型プログラミングに依存するため、Javaでは実質的に実装不可能であることです。
なぜAkka Streamsなのか?
AkkaStreamsは、安全性・簡潔さ・親しみやすさにおいて絶妙なバランスを提供します。AkkaStreamsは、正しく要求を実現できるするために実施ができることを意図的に制約します。(※『目的を達成するための手段をたくさん提供せずに、限られた手段した提供しない』ということか?) しかし、Iterateeでの制約ほどではありません。 概念的には、AkkaStreamsもIterateeも関数的な方法と命令的な方法の両方を提供し、ほとんどの開発者にとっては十分になじみがあります。AkkaStreamsはまたファーストクラスのJavaAPIを有しており、どのような入出力データの要求もJavaで容易に実装することができます。どこでAkkaStreamsが使用されているのか?
PlayのアプリケーションでAkkaStremsに遭遇するであろう場所は以下のとおりです。 - Filter - レスポンスボディのストリーミング - リクエストボディのパース - WebSocket - WSクライアントのレスポンスのストリーミングReactive Streams
ReactiveStreamsは非同期データ入出力のための新しい仕様であり、それはJDK9に含まれることが予定されており、 JDK6以上向けの独立したライブラリとして利用できます。 一般的には、それはエンドユーザ向けのライブラリではなく、むしろ入出力データ用ライブラリが データを互いに統合するための実装をすることのできるSPIです。AkkaStreamsとIterateeは両方ともReactiveなデータ入出力にSPI実装を提供します。これは、IterateeのコードはPlayの新しいAkkaStreamsと一緒に容易に使われることができることを意味します。それはまた、他のReactiveなデータ入出力の実装がPlayで使用されうることをも意味します。Iterateeの未来
Iterateeにはまだ有用なユースケースがあります。 現在、IterateeをPlayから排除する予定はありません。しかし、独立したライブラリに移行されるかもしれません。IterateeがReactiveなデータ入出力の実装を提供してきたおり、IterateeはこれからもPlayで利用できるでしょう。WebSocketの枠組みを超えたより良い操作
Play2.5のWebSocketのAPIはWebSocketの枠組みを超えた直接的な操作を提供します。 あなたはバイナリ、テキスト、Pingとそれに対する応答の送受信できます。(『close frames』はどう訳すべき?) このささいなことに悩みたくないのであれば、PlayはJSONまたはXMLのデータを自動的にWebSocketの枠組みに変換します。新しいJavaのAPI
Play2.5のJavaのAPIは、ScalaのAPIと同等の機能を提供します。これを実現するために、いくつかの新しいJavaのAPIを導入しています。 ・HttpRequestHandlerは、routerにデータが送られる前にリクエストの割込みを可能にするためのものです。 ・EssentialActionは、EssentialFilterやHttpRequestHandlerの中で使用されている低レベルなアクションです。 ・EssentialFilter/FilterはJavaでフィルタを書くためのものです。 ・BodyParserは、Javaでカスタムボディパーサを書くためのものです。Java8のクラスを使用するためにアップグレードされたJavaAPI
Play2.0が2012年にリリースされた時、JavaはPlayの非同期は関数型プログラミングのスタイルのためのサポートを少ししか有していませんでした。ラムダ式はなく、Futuerはブロッキングなインタフェースしか有しておらず、共通的な関数クラスは存在しませんでした。Playはギャップを埋めるために独自のクラスを提供していました。Play2.5ではその状況は変わりました。Java8ではPlayのプログラミングスタイルのためのより良いサポートを提供しています。Play2.5において、JavaのAPIはJava8の標準クラスを使用するために取り除かれました。これは、Playのアプリケーションは他のJavaライブラリをより良く統合できることを意味します。
以下が主な変更点です。
・Javaの関数型インタフェースの使用(Runnnable、Consumer、Predicateなど)
・PlayのF.Optionの代わりにJava8のOptionalを使用
・PlayのF.Promiseの代わりにJava8のCompletionStageを使用
他のロギングフレームワークの使用
多くのユーザは自分が選択したロギングフレームワークをしたいですが、Play2.5まではこれが不可能でした。 現在では、PlayのLogbackに固定された依存は取り除かれており、PlayアプリケーションはSLF4Jと互換性のあるどんなロギングフレームワークでも使用できます。Logbackはデフォルトで含まれていますが、build.sbtに設定することでLogbackを無効にし、自分が選択したフレームワークに置き換えることができます。Playで他のロギングフレームワークを使用するための詳しい情報についてはロギングに関するPlayのドキュメントを参照してください。Playアプリケーションはその設定を少し変更する必要があるでしょう。なぜなら、PlayのLogbackクラスの1つが変更の一環で別のパッケージに移管されたからです。詳細はマイグレーションガイドを参照してください。