イベント

イベントは、ある Bean が「何かが起きた」と知らせ、ほかの任意の数の Bean がそれに反応する仕組みです。

使う理由

イベントがなければ、注文サービスがメール送信、在庫、分析のサービスを自分で呼び出すことになります。反応を一つ増やすたびに注文サービスを書き換える必要があります。イベントを使えば、注文サービスは「注文が入った」と発行するだけです。メール、在庫、分析はそれを受け取ります。どちらも相手を知りません。

イベントは、発行側の本来の仕事ではない反応に使います。呼び出し側が結果を必要とする場合は使わず、相手の Bean を直接呼び出してください。

コンテキスト自身も、すべての Bean の準備ができたときの ContextRefreshedEvent など、自分についてのイベントを発行します。

例

import 'package:spring_core_dart/spring_core_dart.dart';

// どんなオブジェクトもイベントにできる。基底クラスは不要。
class OrderPlaced {
  const OrderPlaced(this.id, this.total);
  final String id;
  final double total;
}

@Service()
class Orders {
  Orders(this.events);

  // パブリッシャーとしてコンテキスト自身が注入される。
  final ApplicationEventPublisher events;

  void place(String id, double total) =>
      events.publishEvent(OrderPlaced(id, total));
}

@Component()
@Log()
class Analytics {
  // OrderPlaced が発行されるたびに呼ばれる。
  @EventListener()
  void onPlaced(OrderPlaced order) => log.info('order ${order.id}');
}

デフォルトでは、リスナーは publishEvent の中で実行されるため、発行側はその完了を待ちます。@Async を付けると、そのリスナーだけこの動作が変わります。

ページ一覧

Spring (Java) との対応

@Service
class Orders {
  private final ApplicationEventPublisher events;
  Orders(ApplicationEventPublisher events) { this.events = events; }

  void place(String id, double total) {
    events.publishEvent(new OrderPlaced(id, total));
  }
}

@Component
class Analytics {
  @EventListener
  void onPlaced(OrderPlaced order) { ... }
}

モデルは同じです。主な違いは、リスナーの条件が SpEL の文字列ではなく Dart の関数であること、そして @Async が @EventListener メソッドにしか使えないことです。

関連項目