5

我想我了解 CDI 的工作原理,为了深入研究它,我想尝试将它与现实世界的示例一起使用。我被一件事困住了,我需要你的帮助才能让我理解。我非常感谢您在这方面的帮助。

我有自己的工作流框架,使用 Java 反射 API 和 XML 配置开发,其中基于特定类型的“源”和“事件名称”我加载适当的模块类并在其上调用“过程”方法。在我们的项目中一切正常。

我对 CDI 功能感到兴奋,并想尝试使用工作流框架,我计划在其中注入模块类,而不是使用反射等加载它们......

只是为了给你一个想法,我会尽量在这里保持简单。

“Message.java”是一种Transfer Object,它带有“Source”和“eventName”,以便我们可以适当地加载模块。

public class Message{
private String source;
private String eventName;
}

模块配置如下

<modules>
<module>
    <source>A</source>
    <eventName>validate</eventName>
    <moduleClass>ValidatorModule</moduleClass>
</module>
<module>
    <source>B</source>
    <eventName>generate</eventName>
    <moduleClass>GeneratorModule</moduleClass>
</module>
</modules>

模块加载器.java

public class ModuleLoader {
public void loadAndProcess(Message message){
    String source=message.getSource();
    String eventName=message.getEventName();

    //Load Module based on above values.

}
}

问题

现在,如果我想通过 CDI 实现相同的功能以注入一个模块(在 ModuleLoader 类中),我可以使用 @Produce 方法编写工厂类,它可以做到这一点。但我的问题是,

a) 如何将 Message Object 传递给 @Produce 方法以根据 eventName 和 source 进行查找?

你能给我一些建议吗?

提前致谢。

4

3 回答 3

4

这个有点棘手,因为 CDI 的工作方式与您的自定义解决方案不同(如果我理解正确的话)。CDI 必须在启动时拥有所有依赖项列表和这些依赖项的解决方案,您的解决方案听起来像是在运行时找到了可能发生变化的所有内容。话虽如此,您可以尝试几件事。

您可以尝试将 anInjectionPoint作为参数注入生产者方法并返回正确的对象,或创建正确的类型。

还有创建您自己的扩展来执行此操作,并创建依赖项并将它们全部连接到扩展中(查看ProcessInjectionTargetProcessAnnotatedType和 'AfterBeanDiscovery` 事件。这两个 快速入门也可能有助于获得一些想法。

于 2012-12-30T21:38:59.810 回答
4

我认为您可能在制作人方面走错了路。相反,特别是根据您所描述的内容,使用观察者可能会更好。

我假设“消息”传输对象像系统范围的事件一样抽象地使用,基本上您触发事件并且您希望在您创建的 XML 框架中定义一些处理程序来确定事件的正确管理器,实例化它(如果需要),然后调用传递事件的类。


@ApplicationScoped 
public class MyMessageObserver {

    public void handleMessageEvent(@Observes Message message) {
        //Load Module based on above values and process the event
    }
}

现在让我们假设你想使用你的原始界面(我猜它看起来像):


public interface IMessageHandler {
     public void handleMessage(final Message message);
}

@ApplicationScoped
public class EventMessageHandler implements IMessageHandler {

    @Inject
    private Event<Message> messageEvent;

    public void handleMessage(Message message) {
        messageEvent.fire(message);
    }
}

然后在您想要使用它的任何遗留类中: @Inject IMessageHandler handler;

这将允许您执行您所描述的所有操作。

于 2013-06-18T03:04:34.610 回答
2

可能你需要这样的东西:

  1. 你需要预选赛。像@Module这样的注解,它需要两个参数source和eventName;它们应该是非限定符值。请参阅文档。

  2. 其次,您需要一个生产者:

    @Produces  
    @Module  
    public Module makeAmodule(InjectionPoint ip) {  
       // load the module, take source and eventName from ip  
    }
    
  3. 像这样在适当的地方注入:

    @Inject
    @Module(source="A", eventName="validate")
    Module modulA;
    

该解决方案只有一个问题,这些模块必须是依赖范围,否则系统将注入相同的模块,无论源和事件名称。如果要使用范围,则需要 make source 和 eventName 限定参数,并且:

  • 为 CDI 做一个扩展,以编程方式注册生产者
  • 或者为 source 和 eventName 的每一种可能的组合制作生产者方法(我不认为这很好)
于 2014-06-17T20:40:14.397 回答