如何动态加载 CDI 事件观察器?

How to load CDI event observers dynamically?

我在 JBoss / Wildfly 上有一个应用程序 运行。我使用 CDI 事件在模块之间进行通信。我希望能够使用事件作为插入自定义的一种方式,基本上是动态加载一个额外的观察者,该观察者也将接收 CDI 事件。

这是我用来从 EJB 中动态加载 classes 的片段:

File file = new File("D:\workspace\integrator\target\classes\");
            
URL url = file.toURI().toURL();
URL[] urls = new URL[]{url};

ClassLoader cl = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());

Class cls = cl.loadClass("demo.DemoObserver");
observerInstance=cls.newInstance();

加载的class非常简单,只是一个普通的CDI事件观察器,被注解为@Dependent,被“看”成一个bean。我的 beans.xml 配置为自动发现 bean。

@Dependent
public class DemoObserver {
    
    private boolean observed=false;
    
    public DemoObserver() {
        observed=false;
    }
    
    @PermitAll
    public void stateChanged(@Observes EquipmentE10StateChanged event) {
            observed=true;
            System.out.println("Demo observer received event E10 state changed: " + event.toString());
    }

}

class 已加载并实例化(我可以看到来自其构造函数的日志),但它从未接收到事件。

我能做些什么来让它工作吗?

有很多方法可以回答真正被问到的问题,但目前我会坚持按要求回答问题。

因为 CDI 强调类型安全,所以它在启动时计算 bean 之间的连接(和观察者方法等),然后将其锁定。所以一般来说,如果你有一个 class-that-is-annotated-to-be-a-bean 并且无论出于什么原因它在启动时没有被“看到”,你就不能“让它”在以后被“看到”。如果在可移植扩展具有 运行 并且容器启动并 运行ning 之后,您有四个观察者方法,那么这就是将永远存在的观察者方法的总数。这是设计使然。

(此外,在您的示例中,您可能确实有一个 bean class 但您是通过自己的 newInstance() 调用手动创建它的。在 CDI 中,一般来说,如果您是用 new 做某事,很可能你在某种程度上做错了™。)

这意味着假设您在启动时什么都不知道,您将需要一个观察者方法来观察您感兴趣的最抽象的事件,然后对其进行动态调度确实需要通知。

或者,如果您在启动时知道 潜在 观察者的“封闭世界”——也许有 EquipmentE10 观察者和 EquipmentE09 观察者和就是这样——您可以创建一个适合它们中的每一个的观察者方法,并使用事件子类型和限定符的某种组合来选择哪些被通知。但是,请注意 event qualifiers and payloads are somewhat counterintuitive.