Наблюдатель 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).