我有两个 SLSB:
BeanF
,BeanO
在两个 ejb-jar 中:
ModF
,ModO
。
BeanF
触发一个事件,而 BeanO
观察它。
第一个 fire(-)
操作以异常结束 (Wildfly 8.2):
ERROR [org.jboss.as.ejb3.invocation] JBAS014134: EJB Invocation failed on component BeanF for method public void BeanF.publish(ModEvent):
javax.ejb.EJBException: org.jboss.msc.service.ServiceNotFoundException: Service service
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?
最佳答案
其他实验
尝试使用 @Singleton
和 @Startup
注释两个 bean,并收到相同的异常(我无法使用 @DependsOn 注释
因为 BeanF
( BeanO )ModF
看不到 ModO
)。
还尝试将 BeanO 更改为 @ApplicationScoped 在这种情况下可以接收事件 - BeanO.observe(@Observes ...) 方法开始执行,执行了一些日志记录,但在尝试调用其他 @Stateless
bean 时崩溃并出现 ServiceNotFoundException
异常(此其他 bean 必须是 @Stateless
因为它使用 TransactionAttributeType.REQUIRES_NEW
注释)。
CDI 解决方案
有点丑陋但可行的解决方案:缓存/排队事件:将 BeanO
拆分为两个 bean:BeanO1
和 BeanO2
。让 BeanO1
是一个 @ApplicationScoped
bean,让它观察事件并通过调用一些空方法并捕获 来检测
。如果 BeanO2
是否准备好ServiceNotFoundExceptionBeanO2
不存在,则事件将在 BeanO1
的 ConcurrentLinkedQueue
中排队。 BeanO2
是无状态的,除了观察之外,它可以执行 BeanO
所做的所有事情。当事件到达并且 BeanO2
准备就绪时,BeanO1
首先从队列中推送事件。仅当将存在实际触发处理旧事件的其他事件时,这是可接受的。
JMS
我认为使用 JMS 将是最干净的解决方案,但也存在一些陷阱:
- 如果使用
topic
,那么我们可能会再次陷入原来的问题 - 订阅者在发送第一条消息后注册(不确定规范,但如果没有消息,消息就会丢失)订阅者)。 - 如果使用
queue
,则当在其他产品中使用ModF
并且没有ModO
时,可能会出现问题 - 队列将膨胀,这可能不是 super 肠道。- 也许
ModF
可以定义一些读取所有事件的MDB
并丢弃它们,并且ModO
以某种方式注册自己的MDB
具有更高优先级的(只是猜测,不知道这是否可能) - 也许
ModO
可以包含一个带有队列名称的配置文本文件,以便ModF
可以读取该文件,动态初始化与队列的连接并将事件放入该队列(如果没有ModO
并且没有文件,则ModF
不会触发事件。
- 也许
关于events - 事件触发时 CDI 观察器尚未初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29488876/