为什么 Event.fireAsync() 需要 @ObservesAsync 注释?

bra*_*zzi 3 java events cdi cdi-2.0 jakarta-ee

在 CDI 2.0 中,可以通过调用异步触发事件Event.fireAsync(),然后使用带@ObservesAsync注释的侦听器侦听此事件。

为什么我们需要Event.firesAsync()@ObservesAsync

  • CDI 2.0 不能异步处理由 触发Event.fire()和捕获的事件@ObservesAsync吗?
  • 或者Event.fireAsync()反过来说,为什么 CDI 2.0 不能异步处理由和 cauguth触发的事件@Observes

Sil*_*rus 9

确实是一个很好的问题,这里有一些见解。

CDI EG(专家组)出于以下几个原因决定不将这两者混合使用:

  • 向后兼容
    • 现有的应用程序使用同步,它需要表现得一样
    • 保持相同的注释需要您添加额外的选项来区分
  • 返回类型
    • 调用Event.fireAsync()为您提供了一个CompletionStage,您可以使用exceptionally()thenApply()等链接后续步骤。这自然适合异步编程模型。
    • Good oldEvent.fire()只给你void,你根本无法做出反应-不利于异步
    • 同样,由于向后兼容,无法更改同步的返回值
  • 例外处理差异很大
    • 同步通知中的异常 == 链尾,你炸了
    • 异步通知中的异常 == 您继续从观察者方法(可能来自多个线程!)收集所有异常,然后将它们呈现给调用代码。既然是CompletionStage,你可以很容易地对此做出反应。
    • 将两者混合会导致用户方面的结果非常混乱——你什么时候会爆炸,什么时候继续?什么是真正的结果Event.fire()(如果它也是异步的)
  • 内部观察者处理
    • 混合同步和异步会非常复杂(假设它甚至是可能的)
    • 请记住,您需要在同步和异步之间严格划一条线,因为上下文不会在其他线程中传播(例如,RequestScoped需要在异步观察者线程中由 Weld 重新激活)
    • 集成商的安全上下文传播也会带来类似的麻烦
    • 通常对观察者进行预处理以使其工作得非常快,如果您对两者都有一种观察者方法,则无法真正对其进行预处理,因为您永远不知道它将用于什么

我能想到的当前模型的其他优点:

  • 存在fireAsync()允许您使用其他选项触发事件
  • 最后但并非最不重要的 - 用户体验
    • 这样很明显,你之前的工作完全一样
    • 那对fireAsync()你有匹配@ObservesAsync