为什么我的 CDI 启动 class 被调用了两次?

Why is my CDI startup class called twice?

在 .war 部署到 Payara 后,我正在使用以下 class 进行一些初始化。而且我可以看到 init() 方法实际上在应用程序启动期间被调用了两次。

package mypackage;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
import javax.inject.Inject;

import lombok.extern.log4j.Log4j2;

@Log4j2
@ApplicationScoped
public class StartupService {

    @Inject LogConfig logConfig;

    void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
        log.debug("### STARTUP SERVICE CALLED ###");

        logConfig.startup();
    }
}

有人可以向我解释为什么这会被调用两次吗?我该如何避免?

我的意思是,我当然可以实现一个静态布尔标志来识别我之前已经被调用过一次,但我更愿意修复根本原因并且从一开始只被调用一次。

好吧,我会试着总结一下,事实可能并非如此,我可以尝试更深入地挖掘。但这是我认为正在发生的事情......

您获得了两次事件,每次都有不同的负载。 这可能有多种原因,但最有可能的原因是 Paraya 在集成方面存在微小缺陷。 Weld 建议集成商通过 SPI 定义其运行的环境。如果他们不这样做,Weld 可以处理它,但需要做一些假设和猜测以满足规范要求。

在这种情况下,我怀疑 Paraya 错误地定义了 Environment 并且 Weld 不确定要触发哪些事件 - 对于 Web 模块,需要使用 ServletContext 负载触发事件,而模块的其余部分有普通的 Object 作为有效载荷。

遗憾的是,除了抢先获得有关环境的信息外,没有简单的方法可以防止这两个事件被触发。原因是 Weld 需要在 Web 模块的任何挂钩处于活动状态之前很久就决定 Object 有效载荷事件。

您的解决方案可能是将 Object 指定为更具体的类型 - 这样只会观察到一个事件。根据您的示例,我假设 ServletContext 有效载荷将是您正在寻找的那个。