コンテキストイベント

コンテキストイベントは、アプリケーションコンテキストが自分のライフサイクル (refreshed、started、stopped、paused、restarted、closed) について発行するイベントです。

使う理由

処理によっては、一つの Bean が作られたときではなく、コンテキストのライフサイクルの特定の時点で行う必要があります。

アプリケーションはこれらのイベントを受け取るだけで、作ることはありません。@EventListener メソッド、ApplicationListener、または context.addListener で受け取ります。一つの Bean の初期化なら @PostConstruct のほうが簡単です。

例

import 'package:spring_core_dart/spring_core_dart.dart';

abstract interface class SessionRepository {
  void saveAll();
}

@Component()
@Log()
class Lifecycle {
  Lifecycle(this.sessions);
  final SessionRepository sessions;

  // すべての eager なシングルトンが存在し、自動起動の Bean が動いている。
  @EventListener()
  void onReady(ContextRefreshedEvent event) =>
      log.info('ready: ${event.applicationContext.id}');

  // close() の最初の段階。ここではまだ他の Bean を使える。
  @EventListener()
  void onClose(ContextClosedEvent event) => sessions.saveAll();
}

基底クラス ApplicationContextEvent を受け取ると、すべてのコンテキストイベントを受け取れます:

@Component()
@Log()
class ContextLog {
  @EventListener()
  void on(ApplicationContextEvent event) =>
      log.info('${event.runtimeType} of ${event.applicationContext.id}');
}

メンバー

イベント 発行されるとき 補足
ApplicationContextEvent (基底クラス) applicationContext はイベントを起こしたコンテキストで、source と同じオブジェクト。
ContextRefreshedEvent refresh() の最後の段階。すべての eager なシングルトンが存在し、自動起動のライフサイクル Bean が動いている。 リスナーが例外を投げるとリフレッシュは失敗する (マルチキャスターにエラーハンドラーがある場合を除く)。
ContextStartedEvent 明示的な start() の後。通常は stop() の後。 最初の起動時には発行されない。
ContextStoppedEvent stop() の後。動いていたライフサイクル Bean が止まっている。 Bean はまだ存在する。close() では発行されない。
ContextRestartedEvent restart() の後。自動起動のライフサイクル Bean が再び動く。 ContextStartedEvent のサブクラス。Spring 7 で追加。
ContextPausedEvent pause() または pauseAsync() の後。一時停止可能なライフサイクル Bean が止まっている。 ContextStoppedEvent のサブクラス。Spring 7 で追加。
ContextClosedEvent close() の最初の段階。すべての Bean がまだ使える。 リスナーのエラーはログに出され、シャットダウンは続く。

子コンテキストで発行されたイベントは、親のリスナーにも届きます。区別が必要なときは applicationContext を比較してください。

Spring (Java) との対応

@Component
class Lifecycle {
  @EventListener
  void onReady(ContextRefreshedEvent event) { ... }

  @EventListener
  void onClose(ContextClosedEvent event) { sessions.saveAll(); }
}

イベントとその順序は Spring 7 と同じです。Spring Boot (spring_boot_dart) を使う場合、ApplicationReadyEvent はランナーの後に発行されるため、「アプリケーションの準備ができた」時点としては通常 ContextRefreshedEvent より適しています。

関連項目