ApplicationEvent
ApplicationEvent はイベントの任意の基底クラスです。このページでは、イベントを送る ApplicationEventPublisher と、イベントを受け取るリスナーの型も扱います。
使う理由
イベントを発行するとき、または @EventListener メソッドがリスナーの形として合わないときに、これらの型を使います。
ApplicationEventPublisher: 何かを知らせる Bean に注入します。すべてのアプリケーションコンテキストはパブリッシャーであり、この型にはコンテキスト自身が注入されます。ApplicationEvent: リスナーがsource(イベントを起こしたオブジェクト) とtimestampを必要とするときに継承します。そうでなければ、普通のクラスやレコードで十分です。PayloadApplicationEvent<T>:ApplicationEventでないオブジェクトが発行されたときに、コンテキストがかぶせる封筒です。Tのリスナーはオブジェクトそのものを受け取ります。発行元とタイムスタンプも必要なときだけ、封筒のほうを受け取ります。ApplicationListener<E>: インターフェースを実装して一つのイベント型を受け取る Bean です。クラスが受信のためだけにある場合や、Java から移植したコードで使います。@EventListenerメソッドのほうが短く書けます。GenericApplicationListenerとSmartApplicationListener: イベントごとに、またはイベントと発行元の型によって、処理するかどうかを決めるリスナーです。context.addListener<E>(...): Flutter のウィジェットやテストなど、Bean でないコードのためのリスナーです。ListenerRegistrationを返し、remove()を呼ぶと受信をやめます。
例
import 'package:spring_core_dart/spring_core_dart.dart';
// 発行元とタイムスタンプを持つイベント。
class OrderShipped extends ApplicationEvent {
OrderShipped(super.source, this.id);
final String id;
}
@Service()
class ShippingService {
ShippingService(this.publisher);
final ApplicationEventPublisher publisher;
// `this` がイベントの発行元として記録される。
void ship(String id) => publisher.publishEvent(OrderShipped(this, id));
}
// 受信のためだけにあるクラス。
@Component()
@Log()
class ShipmentAudit implements ApplicationListener<OrderShipped> {
@override
void onApplicationEvent(OrderShipped event) =>
log.info('shipped ${event.id} at ${event.timestamp}');
}
Bean でないコードから受信する例:
const log = SpringLog('neon.ui');
final context = ApplicationContext.run([appBeans]);
// remove() を呼ぶまで有効。たとえばウィジェットの dispose で呼ぶ。
final registration = context.addListener<OrderShipped>(
(event) => log.info('shipped ${event.id}'),
);
context.getBean<ShippingService>().ship('A-17');
registration.remove();
context.close();
イベントごとに判断するリスナーの例:
const log = SpringLog('neon.audit');
// リフレッシュ以外のすべてのイベントを監査する。
class AuditAll implements GenericApplicationListener {
@override
bool supportsEvent(Object event) => event is! ContextRefreshedEvent;
@override
void onApplicationEvent(Object event) => log.info('audit: $event');
}
context.addApplicationListener(AuditAll());
メンバー
| 型 | メンバー | 意味 |
|---|---|---|
ApplicationEvent |
ApplicationEvent(Object source, {DateTime? timestamp}) |
source が起こしたイベントを作る。timestamp のデフォルトは現在時刻。 |
ApplicationEvent |
source |
イベントを起こしたオブジェクト。通常は発行した Bean。 |
ApplicationEvent |
timestamp |
イベントが作られた時刻 (受信した時刻ではない)。 |
PayloadApplicationEvent<T> |
payload |
発行されたオブジェクト。 |
ApplicationEventPublisher |
publishEvent<T>(T event) |
受け付けるすべてのリスナーに event を届ける。ApplicationEvent でないものは PayloadApplicationEvent<T> に包まれる。 |
ApplicationListener<E> |
onApplicationEvent(E event) |
型 E のイベント (または発行されたオブジェクト) ごとに呼ばれる。 |
GenericApplicationListener |
supportsEvent(Object event) |
このイベントを onApplicationEvent に渡すかどうか。 |
SmartApplicationListener |
supportsEventType(Type)、supportsSourceType(Type) |
実行時の正確な型で判断する。デフォルトの順序が最低優先度の mixin。 |
ApplicationListenerAdapter |
of<E>(handler, {order})、forListener<E>(listener, {order}) |
関数や Bean でない ApplicationListener を、addApplicationListener 用のリスナーにする。 |
ApplicationContext |
addListener<E>(listener, {order}) |
関数のリスナーを追加し、ListenerRegistration を返す。 |
ListenerRegistration |
remove()、isRemoved |
リスナーを止める。2 回目以降の呼び出しは何もしない。 |
Spring (Java) との対応
class OrderShipped extends ApplicationEvent {
final String id;
OrderShipped(Object source, String id) { super(source); this.id = id; }
}
@Component
class ShipmentAudit implements ApplicationListener<OrderShipped> {
public void onApplicationEvent(OrderShipped event) { ... }
}
context.addApplicationListener(ApplicationListener.forPayload(
(OrderPlaced order) -> log.info("placed " + order.id())));
重要な違い:
GenericApplicationListener.supportsEventは、ResolvableTypeではなくイベントのインスタンスで判断します。addListenerはListenerRegistrationを返します。Spring にはこのようなハンドルがなく、リスナーを保持してremoveApplicationListenerを呼びます。registerSingletonに渡すリスナーオブジェクトがApplicationListener<E>の場合は、ApplicationListenerAdapter.forListener<E>で包む必要があります。Dart は実行時にオブジェクトからEを読み取れないためです。