CDI观察员在事件被触发时尚未初始化

时间:2015-04-07 10:01:27

标签: events cdi wildfly java-ee-7 ejb-jar.xml

我有两个SLSB:

  • BeanF
  • BeanO

在两个ejb-jar中:

  • ModF
  • ModO

BeanF触发一个事件,BeanO观察它。

第一个fire(-)操作以异常(Wildfly 8.2)结束:

  

错误[org.jboss.as.ejb3.invocation] JBAS014134:对于方法public void BeanF.publish(ModEvent),组件BeanF上的EJB调用失败:
  javax.ejb.EJBException:org.jboss.msc.service.ServiceNotFoundException:服务服务
  jboss.deployment.subunit。“myapp.ear”。“modO.jar”.component.BeanO.VIEW。“BeanO”.LOCAL not found

进一步fire(-)次操作到达观察者但我不能让任何事件丢失。

是否有办法在事件被触发之前强制的观察者初始化(或者在事件被触发并等待处理后动态执行)?

@Observes(notifyObserver = Reception.IF_EXISTS)只允许在观察者尚未准备就绪时以静默方式跳过事件。
在我的情况下,BeanF不能依赖BeanO因为ModO必须在ModF application.xml之后宣布。

是否可以使用CDI事件/监听器,还是需要使用JMS?

2 个答案:

答案 0 :(得分:3)

其他实验

尝试使用@Singleton@Startup注释两个bean并收到相同的异常(我无法使用BeanF注释@DependsOn( BeanO )因为ModF没有看到{{} 1}})。 还尝试将ModO更改为BeanO,在这种情况下可以接收事件 - @ApplicationScoped方法已开始执行,执行了一些日志记录但在尝试调用时因BeanO.observe(@Observes ...)异常而崩溃其他一些ServiceNotFoundException bean(另一个bean必须是@Stateless,因为它使用@Stateless注释。

CDI解决方案

有点难看但有效的解决方案:缓存/排队事件:将TransactionAttributeType.REQUIRES_NEW拆分为两个bean:BeanOBeanO1。让BeanO2成为BeanO1 bean,让它观察事件并通过调用一些空洞方法并捕获@ApplicationScoped来检测BeanO2是否准备就绪。如果ServiceNotFoundException不存在,那么该事件将在BeanO2 ConcurrentLinkedQueue中排队。 BeanO1是无国籍的,除了观察之外,做BeanO2正在做的所有事情。当事件到达并且BeanO准备就绪时,BeanO2首先从队列中推送事件。只有在成为实际触发处理旧事件的其他事件时才可以接受。

JMS

我想使用JMS将是最干净的解决方案,但也有一些陷阱:

  • 如果使用BeanO1,那么我们可能会再次陷入原始问题 - 用户在发送第一条消息后进行注册(不确定规范,但是当没有订户时消息会丢失)。
  • 如果使用了topic,则在某些其他产品中使用queue并且没有ModF时可能会出现问题 - 队列会膨胀,这可能不是超级肠道。
    • 也许ModO可以定义一些ModF读取所有事件丢弃它们,MDB以某种方式注册自己的ModO具有更高优先级(只是猜测,不知道)如果可能的话)
    • 也许MDB可以包含具有队列名称的配置文本文件,因此ModO可以读取该文件,动态初始化与队列的连接并将事件放入此队列(如果没有{{ 1}}并且没有文件,然后ModF)不会触发事件。

答案 1 :(得分:1)

首先,我认为CDI创建了一个bean的“新”实例并将事件传递给它

  • 没有活动的上下文实例(在当前范围内)和
  • 观察者不是有条件的

我写了这篇here

所以这种行为很奇怪IMO

就替代方案而言 - 是否可以将观察者方法声明为“静态”? CDI肯定会在那种情况下调用它

另外,如果您还没有,我强烈建议您阅读CDI规范文档(第10章和第5.5.6节)