イベント
イベントは、ある 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 を付けると、そのリスナーだけこの動作が変わります。
ページ一覧
- @EventListener: 引数の型のイベントごとに呼ばれる Bean のメソッド。条件と順序の指定も扱います。
- @Async: リスナーを
TaskExecutor上で実行し、発行側を待たせません。 - ApplicationEvent: イベントの基底クラス、パブリッシャー、リスナーのインターフェース。
- コンテキストイベント: コンテキストが自分について発行するイベント (refreshed、started、stopped、closed など)。
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 メソッドにしか使えないことです。