ドキュメント

§プラグインからモジュールへの移行

注記: 非推奨のplay.Pluginシステムは、2.5.xから削除されました。

Playプラグインを実装している場合は、非推奨のJava play.PluginまたはScala play.api.Pluginタイプではなく、play.api.inject.Moduleを使用して実装を移行することを検討してください。

古いPlugin APIと、Moduleを使用する新しいAPIの主な違いは、後者では依存性注入(DI)を完全に採用することです。PlayがDIについて意見を持つようになった理由についてはこちらを参照してください。

§理由

古いPlugin APIでは、ロードするプラグインの数と完全修飾名を含むplay.pluginsファイルを提供する必要がありました。この数は、Playによってプラグイン間の合計順序を決定するために使用されました。このアプローチは、数が初期化順序の正しい場所に一致することを保証するのが難しいため、プラグインの依存関係がプラグインが初期化される前に初期化される可能性があり、脆かったです。さらに、2つのプラグインが同じ番号を使用することを回避する方法はありませんでした。DIを使用することで、これらの両方の問題が解決されました。コンポーネントは、コンストラクタ引数として依存関係を明示的に宣言し、コンストラクタで初期化を実行するようになりました。

§Moduleクラスの作成

play.api.inject.Moduleを継承するクラスを作成し、bindingsメソッドの実装を提供することから始めます。このメソッドでは、モジュールによって提供されるコンポーネントをユーザーのコードまたは他のモジュールに注入できるように、型を具体的な実装に接続する必要があります。次に例を示します。

Javaの場合

import play.api.Configuration;
import play.api.Environment;
import play.api.inject.Binding;
import play.api.inject.Module;

import scala.collection.Seq;

public class MyModule extends Module {
  public Seq<Binding<?>> bindings(Environment environment, Configuration configuration) {
    return seq(
      bind(MyComponent.class).to(MyComponentImpl.class)
    );
  }
}

Scalaの場合

import play.api.Configuration
import play.api.Environment

class MyModule extends Module {
  def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = {
    Seq(
      bind[MyComponent].to[MyComponentImpl]
    )
  }
}

定義しているコンポーネントが別のコンポーネントを必要とする場合は、@javax.inject.Injectアノテーションをコンストラクタの前に付けることで、必要なコンポーネントをコンストラクタの依存関係として追加するだけで済みます。DIフレームワークがそれ以降の処理を行います。

注記: コンポーネントBがAを必要とする場合、BはAが初期化された後にのみ初期化されます。

次に、MyComponentImplという名前のコンポーネントがApplicationLifecycleコンポーネントを必要とする例を示します。

Javaの場合

import javax.inject.Inject;
import play.inject.ApplicationLifecycle;
import play.libs.F;

public interface MyComponent {}

class MyComponentImpl implements MyComponent {
  @Inject
  public MyComponentImpl(ApplicationLifecycle lifecycle) {
    // previous contents of Plugin.onStart
    lifecycle.addStopHook( () -> {
      // previous contents of Plugin.onStop
      return F.Promise.pure(null);
    });
  }
}

Scalaの場合

import javax.inject.Inject

import scala.concurrent.Future

import play.api.inject.ApplicationLifecycle

trait MyComponent

class MyComponentImpl @Inject() (lifecycle: ApplicationLifecycle) extends MyComponent {
  // previous contents of Plugin.onStart
  lifecycle.addStopHook { () =>
    // previous contents of Plugin.onStop
    Future.successful(())
  }
}

§接続

新しく作成したModuleクラスを有効なモジュールのセットに追加する時間です。これを行うには、設定ファイルに次の行を追加するだけです。

play.modules.enabled  += "my.module.MyModule"

他のプロジェクト(サブプロジェクトを含む)で使用されるライブラリに取り組んでいる場合は、上記の行をreference.confファイルに追加します(まだreference.confがない場合は、作成してsrc/main/resourcesに配置します)。そうでない場合、エンドPlayプロジェクト内にある場合は、application.conf内にある必要があります。
エンドPlayプロジェクトの場合は、`Module`という名前のクラスを作成し、ルートパッケージ(「app」ディレクトリ)に配置することもできます。

注記: ライブラリに取り組んでいる場合は、アプリケーションによってモジュールがロードされるときに非決定的な結果につながる可能性があるため(この問題を参照)、play.modules.disabledを使用してモジュールを無効にすることは強くお勧めしません。実際、play.modules.disabledは、エンドユーザーがデフォルトで有効になっているモジュールをオーバーライドできるようにするためのものです。

§コンパイル時DI

Moduleクラスを定義することで、Google GuiceやSpringなどのランタイムDIフレームワークで使用できるコンポーネントを作成しました。Scalaで人気のある代替手段は、コンパイル時DIです。コンパイル時DIでも使用できるコンポーネントを作成するには、コンポーネントの依存関係を宣言するScalaのtraitを提供します。実行中の例の場合、次のようになります。

import play.api.inject.ApplicationLifecycle

trait MyComponents {
  def applicationLifecycle: ApplicationLifecycle
  lazy val component: MyComponent = new MyComponentImpl(applicationLifecycle)
}

§Pluginクラスとplay.pluginsファイルを削除する

この時点で、コードの移行が成功しているはずです。そのため、Pluginクラスとplay.pluginsファイルの両方を削除する時間です。後者は通常、プロジェクトのconfフォルダーにあります。

次へ: Reactive Streams統合(実験的)


このドキュメントにエラーを見つけましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインを読んだ後、プルリクエストを送信することを遠慮なく行ってください。質問やアドバイスを共有したいですか?コミュニティフォーラムにアクセスして、コミュニティとの会話を開始してください。