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

问题描述

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

这是我用来从EJB内部动态加载类的代码段:

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();

加载的类非常简单,只是一个普通的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());
    }

}

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

有什么我可以做的工作吗?

解决方法

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

因为CDI强调类型安全,所以它在启动时计算bean(以及观察者方法等)之间的连线,然后将其锁定。因此,通常来说,如果您有一个要注释的类,并且由于某种原因在启动时未“看到”该类,则以后就无法“使其”“看到”。如果在运行便携式扩展且容器已启动并运行之后,您有四个观察者方法,那么那将永远存在的观察者方法总数。这是设计使然。

(另外,在您的示例中,您可能确实有一个Bean类,但是您是通过自己的newInstance()调用手动创建的。在CDI中,通常,如果您使用{{1 }},可能是您在某种程度上做错了™。)

这意味着假设您在启动时一无所知,您将需要一个观察者方法,该方法观察您感兴趣的最抽象的事件,然后将其动态分配给该事件。 >确实需要通知。

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...