middle
Как работать с Event Listener в плагине?
Event Listener позволяет реагировать на события в Jira — создание, обновление, удаление задач, комментариев, проектов и других сущностей — через подписку с аннотацией @EventListener.
Реализация через EventPublisher
Код IssueEventListener
@Named
public class IssueEventListener implements InitializingBean, DisposableBean {
private static final Logger log = LoggerFactory.getLogger(IssueEventListener.class);
private final EventPublisher eventPublisher;
private final MailService mailService;
@Inject
public IssueEventListener(@ComponentImport EventPublisher eventPublisher,
MailService mailService) {
this.eventPublisher = eventPublisher;
this.mailService = mailService;
}
@Override
public void afterPropertiesSet() {
eventPublisher.register(this);
}
@Override
public void destroy() {
eventPublisher.unregister(this);
}
@EventListener
public void onIssueCreated(IssueEvent event) {
if (event.getEventTypeId().equals(EventType.ISSUE_CREATED_ID)) {
Issue issue = event.getIssue();
log.info("Создана задача: {} в проекте {}",
issue.getKey(), issue.getProjectObject().getKey());
if ("Bug".equals(issue.getIssueType().getName())
&& "Critical".equals(issue.getPriority().getName())) {
mailService.notifyTeamLead(issue);
}
}
}
@EventListener
public void onIssueUpdated(IssueEvent event) {
if (event.getEventTypeId().equals(EventType.ISSUE_UPDATED_ID)) {
Issue issue = event.getIssue();
ChangeLog changeLog = event.getChangeLog();
if (changeLog != null) {
for (ChangeItemBean change : changeLog.getChangeItemBeans()) {
if ("status".equals(change.getField())) {
log.info("Задача {} сменила статус: {} → {}",
issue.getKey(), change.getFromString(),
change.getToString());
}
}
}
}
}
}
Кастомные события
Пример
// Определение
public class TaskProcessedEvent {
private final String issueKey;
private final String result;
private final Instant processedAt;
public TaskProcessedEvent(String issueKey, String result) {
this.issueKey = issueKey;
this.result = result;
this.processedAt = Instant.now();
}
// getters
}
// Публикация
@Named
public class TaskProcessor {
private final EventPublisher eventPublisher;
@Inject
public TaskProcessor(@ComponentImport EventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void process(String issueKey) {
// ... обработка ...
eventPublisher.publish(new TaskProcessedEvent(issueKey, "SUCCESS"));
}
}
// Подписка
@EventListener
public void onTaskProcessed(TaskProcessedEvent event) {
log.info("Задача {} обработана: {}", event.getIssueKey(), event.getResult());
}
Частые ошибки
- Не дерегистрировать слушатель в
destroy()— при перезагрузке плагина старый слушатель остаётся активным и вызывается дважды - Синхронная тяжёлая обработка — замедляет UI Jira для пользователя
- Изменение issue внутри слушателя без
IssueManager.updateIssue()— изменения теряются или вызывают рекурсивные события - Не обрабатывать исключения — необработанное исключение в listener может сломать операцию пользователя
Как используется в 2026
- Event Listener — стандартный механизм реакции на события в DC-плагинах
- В Cloud аналог — Forge Triggers (
avi:jira:created:issue) - Для сложных event-driven сценариев применяют паттерн: Jira Event -> Plugin Queue -> Async Processor
На собеседовании: обязательно упомяните register/unregister в afterPropertiesSet/destroy — иначе утечка памяти. Listener вызывается синхронно в том же потоке — тяжёлую логику выносите в отдельный поток. Сравните с Event Listener и не забудьте:
IssueEvent.getEventTypeId()— числовой ID, сравнивайте с константами EventType.