
# 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()` を呼ぶと受信をやめます。

## 例

```dart
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 でないコードから受信する例:

```dart
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();
```

イベントごとに判断するリスナーの例:

```dart
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) との対応

```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` を読み取れないためです。

## 関連項目

- [イベント](index.md)
- [@EventListener](event-listener.md)
- [コンテキストイベント](context-events.md)
- [ApplicationContext](../beans/application-context.md)
