基本概念
イベント監視機構はオブザーバーパターンとして理解でき,データ発信者(イベントソース)とデータ受信者(リスナー)で構成される.Javaではイベントオブジェクトはjava.util.EventObjectを継承し,イベントリスナーはjava.util.EventListenerを実装する.EventObjectはデフォルトコンストラクタを持たず,イベント発生源を追跡するためのsourceパラメータが必要となる.
Springのイベントモデル
SpringのイベントオブジェクトはApplicationEventで,EventObjectを継承している.主要な実装は以下の通り:
public abstract class ApplicationEvent extends EventObject {
public ApplicationEvent(Object source) {
super(source);
}
}
イベントリスナーはApplicationListenerインターフェースを実装する:
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void handleEvent(E event);
}
実装手法
Springでイベント監視を実装する主な方法:
- インターフェースベース:ApplicationListenerの実装
- アノテーションベース:@EventListenerの利用
本記事ではインターフェースベースのアプローチに焦点を当てる.
実装例
1. カスタムイベントの定義
public class UserActivityEvent extends ApplicationEvent {
private final UserActionRecord actionRecord;
public UserActivityEvent(UserActionRecord actionRecord) {
super(actionRecord);
this.actionRecord = actionRecord;
}
public UserActionRecord getActionRecord() {
return actionRecord;
}
}
2. ユーザー行動データモデル
public class UserActionRecord implements Serializable {
private Integer userId;
private String loginId;
private String displayName;
private String activityDetail;
private LocalDateTime timestamp;
// コンストラクタとアクセサメソッド
public UserActionRecord(Integer userId, String loginId,
String displayName, LocalDateTime timestamp) {
this.userId = userId;
this.loginId = loginId;
this.displayName = displayName;
this.timestamp = timestamp;
}
}
3. イベントリスナーの登録
@Component
public class ActivityTracker implements ApplicationListener<UserActivityEvent> {
private final ActivityLogService logService;
@Autowired
public ActivityTracker(ActivityLogService logService) {
this.logService = logService;
}
@Override
public void handleEvent(UserActivityEvent event) {
logService.recordAction(event.getActionRecord());
}
}
4. イベント発行の実装
@Component
public class LogoutHandler extends SimpleUrlLogoutSuccessHandler {
private final ApplicationEventPublisher publisher;
private final UserAccountService accountService;
@Autowired
public LogoutHandler(ApplicationEventPublisher publisher,
UserAccountService accountService) {
this.publisher = publisher;
this.accountService = accountService;
}
@Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication auth) {
UserDetails userDetails = (UserDetails) auth.getPrincipal();
UserAccount account = accountService.findByLoginId(userDetails.getUsername());
UserActionRecord action = new UserActionRecord(
account.getId(),
account.getLoginId(),
account.getDisplayName(),
LocalDateTime.now()
);
action.setActivityDetail(account.getLoginId() + " がシステムからログアウトしました");
publisher.publishEvent(new UserActivityEvent(action));
ResponseUtil.sendSuccess(response);
}
}