§コンパイル時依存性注入
Playは、実行時依存性注入のメカニズムをデフォルトで提供しています。つまり、依存関係が実行時まで配線されない依存性注入です。このアプローチには長所と短所の両方があり、主な長所はボイラープレートコードの最小化ですが、主な短所はアプリケーションの構築がコンパイル時に検証されないことです。
Scala開発で人気のある代替アプローチは、コンパイル時依存性注入を使用することです。最も単純な場合、コンパイル時DIは、依存関係を手動で構築および配線することによって実現できます。マクロベースの自動配線ツール、暗黙的な自動配線 teknik 、およびさまざまな形式のケーキパターンなど、他のより高度な teknik とツールが存在します。これらはすべて、コンストラクターと手動配線の上に簡単に実装できるため、Playのコンパイル時依存性注入のサポートは、パブリックコンストラクターとファクトリメソッドをAPIとして提供することによって提供されます。
パブリックコンストラクターとファクトリメソッドを提供することに加えて、Playのすべての標準モジュールは、便宜上、ケーキパターンの軽量な形式を実装するいくつかのトレイトを提供しています。これらはパブリックコンストラクターの上に構築されており、完全にオプションです。一部のアプリケーションでは、使用するのが適切ではありませんが、多くのアプリケーションでは、Playによって提供されるコンポーネントを配線するための非常に便利なメカニズムになります。これらのトレイトは、トレイト名の末尾に `Components` を付けるという命名規則に従います。たとえば、DB APIのデフォルトのHikariCPベースの実装は、HikariCPComponentsと呼ばれるトレイトを提供します。
コンパイル時DIまたはDI全般に慣れていない場合は、Adam WarskiのScalaでのDIガイドを読むことをお勧めします。このガイドでは、コンパイル時DI全般と、彼のMacwireライブラリによって提供されるヘルパーについて説明しています。このアプローチは、Playによって提供される組み込みコンポーネントトレイトと簡単に統合できます。
以下の例では、組み込みコンポーネントヘルパートレイトを使用して、Playアプリケーションを手動で配線する方法を示します。提供されているコンポーネントトレイトのソースコードを読むことで、これを他の依存性注入teknik にも簡単に適用できるはずです。
§アプリケーションのエントリポイント
JVMで実行されるすべてのアプリケーションには、リフレクションによってロードされるエントリポイントが必要です。アプリケーションが自身を起動する場合でも、メインクラスは引き続きリフレクションによってロードされ、そのメインメソッドはリフレクションを使用して見つけて呼び出されます。
Playの開発モードでは、Playで使用されるJVMとHTTPサーバーは、アプリケーションの再起動の間も実行し続ける必要があります。これを実装するために、Playは実装できるApplicationLoaderトレイトを提供しています。アプリケーションローダーは、アプリケーションがリロードされるたびに、アプリケーションをロードするために構築および呼び出されます。
このトレイトのロードメソッドは、引数としてアプリケーションローダーコンテキストを取ります。これには、Playアプリケーション自体よりも長く存続し、アプリケーション自体によって構築できない、Playアプリケーションに必要なすべてのコンポーネントが含まれています。これらのコンポーネントの多くは、開発モードで機能を提供するために khusus に存在します。たとえば、ソースマッパーを使用すると、Playエラーハンドラーは例外がスローされた場所のソースコードをレンダリングできます。
これの最も簡単な実装は、Play BuiltInComponentsFromContext抽象クラスを拡張することによって提供できます。このクラスはコンテキストを取り、そのコンテキストに基づいてすべての組み込みコンポーネントを提供します。提供する必要があるのは、Playがリクエストをルーティングするためのルーターだけです。以下は、この方法で作成できる最も簡単なアプリケーションで、ヌルルーターを使用しています。
import play.api._
import play.api.routing.Router
import play.api.ApplicationLoader.Context
import play.filters.HttpFiltersComponents
class MyApplicationLoader extends ApplicationLoader {
def load(context: Context) = {
new MyComponents(context).application
}
}
class MyComponents(context: Context) extends BuiltInComponentsFromContext(context) with HttpFiltersComponents {
lazy val router = Router.empty
}
このアプリケーションローダーを使用するようにPlayを設定するには、`application.conf`ファイルで`play.application.loader`プロパティを完全修飾クラス名を指すように設定します。
play.application.loader=MyApplicationLoader
さらに、組み込みのGuiceモジュールを使用する既存のプロジェクトを変更している場合は、`build.sbt`の`libraryDependencies`から`guice`を削除できるはずです。
§ロギングの設定
Playでロギングを正しく設定するには、アプリケーションが返される前に `LoggerConfigurator` を実行する必要があります。デフォルトの BuiltInComponentsFromContext は、`LoggerConfigurator` を自動的に呼び出しません。
この初期化コードは、アプリケーションローダーに追加する必要があります
class MyApplicationLoaderWithInitialization extends ApplicationLoader {
def load(context: Context) = {
LoggerConfigurator(context.environment.classLoader).foreach {
_.configure(context.environment, context.initialConfiguration, Map.empty)
}
new MyComponents(context).application
}
}
Play 2.4.xから移行する場合、`LoggerConfigurator` は `Logger.configure()` の代わりであり、さまざまなロギングフレームワークのカスタマイズが可能です。
§ルーターの提供
デフォルトでは、Playは注入されたルートジェネレーターを使用します。これは、ルートファイルに表示される順序で、各コントローラーとルートファイルに含まれるルーターを受け入れるコンストラクターを持つルーターを生成します。ルーターのコンストラクターは、最初の引数として、パラメーターバインディングエラーの処理に使用される`HttpErrorHandler`と、最後の引数としてプレフィックス文字列も受け入れます。これをデフォルトで `"/"` にするオーバーロードされたコンストラクターも提供されます。
次のルート
GET / controllers.Application.index
GET /foo controllers.Application.foo
-> /bar bar.Routes
GET /assets/*file _root_.controllers.Assets.at(path = "/public", file)
は、次のコンストラクターシグネチャを持つルーターを生成します
class Routes(
override val errorHandler: play.api.http.HttpErrorHandler,
Application_0: controllers.Application,
bar_Routes_0: bar.Routes,
Assets_1: controllers.Assets,
val prefix: String
) extends GeneratedRouter {
def this(
errorHandler: play.api.http.HttpErrorHandler,
Application_0: controllers.Application,
bar_Routes_0: bar.Routes,
Assets_1: controllers.Assets
) = this(Application_0, bar_Routes_0, Assets_1, "/")
...
}
パラメーターの命名は意図的に明確に定義されていないことに注意してください(実際には、それらに追加されるインデックスはハッシュマップの順序によってランダムです)。したがって、これらのパラメーターの名前に依存しないでください。
実際のアプリケーションでこのルーターを使用するには
import play.api._
import play.api.ApplicationLoader.Context
import play.filters.HttpFiltersComponents
import router.Routes
class MyApplicationLoader extends ApplicationLoader {
def load(context: Context) = {
new MyComponents(context).application
}
}
class MyComponents(context: Context)
extends BuiltInComponentsFromContext(context)
with HttpFiltersComponents
with controllers.AssetsComponents {
lazy val barRoutes = new bar.Routes(httpErrorHandler)
lazy val applicationController = new controllers.Application(controllerComponents)
lazy val router: Routes = new Routes(httpErrorHandler, applicationController, barRoutes, assets)
}
§他のコンポーネントの使用
前述のように、Playは他のコンポーネントを配線するための多くのヘルパートレイトを提供しています。たとえば、メッセージモジュールを使用する場合、I18nComponents をコンポーネントケーキに混ぜ込むことができます。次のようにします。
import play.api.i18n._
class MyComponents(context: Context)
extends BuiltInComponentsFromContext(context)
with I18nComponents
with HttpFiltersComponents {
lazy val router = Router.empty
lazy val myComponent = new MyComponent(messagesApi)
}
class MyComponent(messages: MessagesApi) {
// ...
}
他のヘルパートレイトも、CSRFComponents または AhcWSComponents として利用できます。
次へ:アプリケーション設定
このドキュメントに誤りを見つけましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインを読んだ後、プルリクエストを送信してください。質問やアドバイスがありますか?コミュニティフォーラムにアクセスして、コミュニティとの会話を始めてください。