[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-jira-kak-rabotat-s-event-listener-v-plagine":3},{"id":4,"slug":5,"topicId":6,"topicSlug":7,"topicName":8,"topicEmoji":9,"question":10,"answer":11,"codeLang":12,"codeSrc":12,"important":12,"commonMistakes":12,"modernUsage":12,"difficulty":13,"tags":14,"related":18,"progress":19,"seo":20},1060,"kak-rabotat-s-event-listener-v-plagine",27,"jira","Jira","📋","Как работать с Event Listener в плагине?","Event Listener позволяет реагировать на события в Jira — создание, обновление, удаление задач, комментариев, проектов и других сущностей — через подписку с аннотацией `@EventListener`.\n\n### Реализация через EventPublisher\n\n\u003Cdetails>\n\u003Csummary>Код IssueEventListener\u003C\u002Fsummary>\n\n```java\n@Named\npublic class IssueEventListener implements InitializingBean, DisposableBean {\n\n    private static final Logger log = LoggerFactory.getLogger(IssueEventListener.class);\n\n    private final EventPublisher eventPublisher;\n    private final MailService mailService;\n\n    @Inject\n    public IssueEventListener(@ComponentImport EventPublisher eventPublisher,\n                              MailService mailService) {\n        this.eventPublisher = eventPublisher;\n        this.mailService = mailService;\n    }\n\n    @Override\n    public void afterPropertiesSet() {\n        eventPublisher.register(this);\n    }\n\n    @Override\n    public void destroy() {\n        eventPublisher.unregister(this);\n    }\n\n    @EventListener\n    public void onIssueCreated(IssueEvent event) {\n        if (event.getEventTypeId().equals(EventType.ISSUE_CREATED_ID)) {\n            Issue issue = event.getIssue();\n            log.info(\"Создана задача: {} в проекте {}\",\n                    issue.getKey(), issue.getProjectObject().getKey());\n\n            if (\"Bug\".equals(issue.getIssueType().getName())\n                    && \"Critical\".equals(issue.getPriority().getName())) {\n                mailService.notifyTeamLead(issue);\n            }\n        }\n    }\n\n    @EventListener\n    public void onIssueUpdated(IssueEvent event) {\n        if (event.getEventTypeId().equals(EventType.ISSUE_UPDATED_ID)) {\n            Issue issue = event.getIssue();\n            ChangeLog changeLog = event.getChangeLog();\n\n            if (changeLog != null) {\n                for (ChangeItemBean change : changeLog.getChangeItemBeans()) {\n                    if (\"status\".equals(change.getField())) {\n                        log.info(\"Задача {} сменила статус: {} → {}\",\n                                issue.getKey(), change.getFromString(),\n                                change.getToString());\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n### Кастомные события\n\n```java\n\u002F\u002F Определение\npublic class TaskProcessedEvent {\n    private final String issueKey;\n    private final String result;\n    private final Instant processedAt;\n\n    public TaskProcessedEvent(String issueKey, String result) {\n        this.issueKey = issueKey;\n        this.result = result;\n        this.processedAt = Instant.now();\n    }\n    \u002F\u002F getters\n}\n\n\u002F\u002F Публикация\n@Named\npublic class TaskProcessor {\n\n    private final EventPublisher eventPublisher;\n\n    @Inject\n    public TaskProcessor(@ComponentImport EventPublisher eventPublisher) {\n        this.eventPublisher = eventPublisher;\n    }\n\n    public void process(String issueKey) {\n        \u002F\u002F ... обработка ...\n        eventPublisher.publish(new TaskProcessedEvent(issueKey, \"SUCCESS\"));\n    }\n}\n\n\u002F\u002F Подписка\n@EventListener\npublic void onTaskProcessed(TaskProcessedEvent event) {\n    log.info(\"Задача {} обработана: {}\", event.getIssueKey(), event.getResult());\n}\n```\n\n### Частые ошибки\n\n- Не дерегистрировать слушатель в `destroy()` — при перезагрузке плагина старый слушатель остаётся активным и вызывается дважды\n- Синхронная тяжёлая обработка — замедляет UI Jira для пользователя\n- Изменение issue внутри слушателя без `IssueManager.updateIssue()` — изменения теряются или вызывают рекурсивные события\n- Не обрабатывать исключения — необработанное исключение в listener может сломать операцию пользователя\n\n### Как используется в 2026\n\n- Event Listener — стандартный механизм реакции на события в DC-плагинах\n- В Cloud аналог — Forge Triggers (`avi:jira:created:issue`)\n- Для сложных event-driven сценариев применяют паттерн: Jira Event -> Plugin Queue -> Async Processor\n\n> **На собеседовании:** обязательно упомяните register\u002Funregister в afterPropertiesSet\u002Fdestroy — иначе утечка памяти. Listener вызывается синхронно в том же потоке — тяжёлую логику выносите в отдельный поток. Сравните с Event Listener и не забудьте: `IssueEvent.getEventTypeId()` — числовой ID, сравнивайте с константами EventType.","","middle",[15,16,17,7],"event-driven","event-listener","jira-plugin",[],null,{"title":21,"description":22,"ogTitle":23,"ogDescription":24,"keywords":25,"schemaAnswer":34,"featuredSnippetReady":35},"Как работать с Event Listener в плагине Jira DC — Gymterview","Event Listener в Jira DC: @EventListener, EventPublisher register\u002Funregister, IssueEvent, кастомные события, асинхронная обработка. Примеры на Java.","Event Listener в Jira DC плагинах: подписка и обработка событий — Gymterview","Как подписаться на события Jira: register\u002Funregister, типы событий, кастомные события, асинхронная обработка тяжёлой логики.",[26,27,28,29,30,31,32,33],"Event Listener","EventPublisher","@EventListener","IssueEvent","Jira события","кастомные события","Jira DC plugin","Java","Event Listener реагирует на события Jira через @EventListener и EventPublisher. Обязательно register в afterPropertiesSet и unregister в destroy (иначе утечка памяти). Listener вызывается синхронно — тяжёлую логику выносите в отдельный поток. IssueEvent.getEventTypeId() сравнивайте с константами EventType. Поддерживаются кастомные события через eventPublisher.publish().",true]