Наблюдатель CDI еще не инициализирован при запуске события

У меня есть два SLSB:

  • BeanF,
  • BeanO

в двух эйб-банках:

  • ModF,
  • ModO,

BeanF запускает событие и BeanO наблюдает за этим.

Первый fire(-) операция заканчивается исключением (Wildfly 8.2):

ОШИБКА [org.jboss.as.ejb3.invocation] JBAS014134: сбой при вызове EJB для компонента BeanF для метода public void BeanF.publish (ModEvent):
javax.ejb.EJBException: org.jboss.msc.service.ServiceNotFoundException: Сервисный сервис
jboss.deployment.subunit."myapp.ear"."modO.jar".component.BeanO.VIEW."BeanO".LOCAL не найден

В дальнейшем fire(-) операции доходят до наблюдателя, но я не могу допустить, чтобы какое-либо событие было потеряно.

Есть ли способ принудительно инициализировать наблюдателя до того, как событие будет запущено (или "на лету" после того, как событие запущено и ожидает обработки)?

@Observes(notifyObserver = Reception.IF_EXISTS) позволяет молча пропустить событие, когда наблюдатель еще не готов.
В моем случае BeanF не может зависеть от BeanO так как ModO должен быть объявлен после ModF в application.xml,

Это возможно с событиями / слушателями CDI, или мне нужно было бы пойти с JMS?

2 ответа

Другие эксперименты

Попробовал аннотировать обе бобы @Singleton а также @Startup и получил то же исключение (я не могу комментировать BeanF с @DependsOn( BeanO ) так как ModF не видит ModO). Также попытался изменить BeanO в @ApplicationScoped и в этом случае событие может быть получено - BeanO.observe(@Observes ...) метод начал выполняться, выполнил некоторые записи, но потерпел неудачу с ServiceNotFoundException Исключение, когда пытался вызвать какой-то другой @Stateless боб (этот другой боб должен быть @Stateless так как он использует TransactionAttributeType.REQUIRES_NEW аннотация).

CDI решение

Немного некрасивое, но рабочее решение: кэширование / организация очередей: split BeanO на две фасоли: BeanO1 а также BeanO2, Позволять BeanO1 быть @ApplicationScoped боб, пусть он наблюдает за событием и обнаружит, если BeanO2 готов, вызывая какой-то пустой метод и ловя ServiceNotFoundException, Если BeanO2 не там, то событие в очереди в ConcurrentLinkedQueue в BeanO1, BeanO2 без гражданства и делает все, что BeanO делал кроме наблюдения. Когда приходит событие и BeanO2 готов тогда BeanO1 сначала выталкивает события из очереди. Это допустимо только тогда, когда будет какое-то другое событие, которое фактически вызовет обработку более старых событий.

JMS

Я думаю, что использование JMS было бы самым чистым решением, но есть и несколько подводных камней:

  • если topic используется, тогда мы снова можем попасть в исходную проблему - подписчик регистрируется после отправки первого сообщения (не уверен насчет спецификации, но после этого сообщение теряется, когда нет подписчиков).
  • если queue используется, тогда проблема может появиться, когда ModF используется в каком-то другом продукте, и нет ModO - очередь будет набухать, и это не может быть супер кишкой.
    • может быть ModF мог бы определить некоторые MDB который читает все события, отбрасывает их и ModO как-то регистрирует свою собственную MDB это имеет более высокий приоритет (просто догадываюсь, не знаю, возможно ли это)
    • может быть ModO может содержать текстовый файл конфигурации с именем очереди, так ModF может прочитать этот файл, инициализировать соединение с очередью на лету и поместить события в эту очередь (если нет ModO и нет файла, то события не запускаются ModF).

Прежде всего, я думаю, что CDI создает "новый" экземпляр компонента и доставляет ему событие в случае, если

  • нет активного контекстного экземпляра (в текущей области), и
  • наблюдатель не условен

Я написал об этом здесь

Так что это поведение странно ИМО

С точки зрения альтернатив - можно ли объявить вам метод наблюдателя как "статический"? CDI, безусловно, будет вызывать его в этом случае

Кроме того, если вы еще этого не сделали, я настоятельно рекомендую прочитать документацию по спецификации CDI (гл. 10 и раздел 5.5.6).

Другие вопросы по тегам