CDI @Producer方法可以采用自定义参数吗?

时间:2012-12-28 22:28:38

标签: cdi

我想我理解CDI是如何工作的,为了深入研究它,我想尝试用一些真实世界的例子。我被困在一件事情,我需要你的帮助才能让我理解。在这方面,我非常感谢你的帮助。

我有自己的工作流框架,使用Java反射API和XML配置开发,基于特定类型的“source”和“eventName”,我加载适当的Module类并在其上调用“process”方法。在我们的项目中,一切都运转良好。

我对CDI功能感到兴奋,并希望尝试使用工作流框架,我计划注入Module类,而不是使用Reflection等加载它们......

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

“Message.java”是一种带有“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>

ModuleLoader.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方法编写Factory类,它可以做到这一点。但我的问题是,

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

你能给我一些建议吗?

提前致谢。

3 个答案:

答案 0 :(得分:4)

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

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

还有创建自己的扩展来执行此操作并创建依赖关系并将它们连接到扩展中(请查看ProcessInjectionTargetProcessAnnotatedType和'AfterBeanDiscovery`事件。这些{{3 }} two也可能有助于获得一些想法。

答案 1 :(得分:3)

我认为你可能会走错了生产者的道路。相反,使用观察者可能会更好,特别是基于你所描述的内容。

我假设“消息”传输对象被抽象地使用,就像系统范围的事件一样,基本上你触发了事件,你想要在你创建的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;

这将允许您完成您所描述的所有事情。

答案 2 :(得分: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;
    
  4. 该解决方案只有一个问题,那些模块必须是依赖范围,否则系统会注入源和eventName的相同模块。 如果要使用范围,则需要生成source和eventName限定参数,并且:

    • 为CDI制作扩展程序,以编程方式注册生产者
    • 或为源和eventName的每个可能组合制作生产者方法(我认为不太好)