【问题标题】:Can CDI @Producer method take custom parameters?CDI @Producer 方法可以接受自定义参数吗?
【发布时间】:2012-12-28 22:28:37
【问题描述】:

我想我了解 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>

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

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

你能给我一些建议吗?

提前致谢。

【问题讨论】:

    标签: cdi


    【解决方案1】:

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

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

    还可以创建自己的扩展来执行此操作并创建依赖项并将它们全部连接到扩展中(看看ProcessInjectionTargetProcessAnnotatedType 和 'AfterBeanDiscovery` 事件。这些two quickstarts 可能也有助于实现一些想法。

    【讨论】:

    • 请注意,InjectionPoint 技巧只有在您 @Produces 一个 Dependent 范围的 bean 时才有效。对于正常范围的 bean(SessionScoped、ApplicationScoped、RequestScoped 等),它工作,因为您有多个注入点,而不仅仅是一个注入点。
    【解决方案2】:

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

    我假设“消息”传输对象像系统范围的事件一样抽象地使用,基本上您触发事件并且您希望在您创建的 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;

    这将允许你做你所描述的一切。

    【讨论】:

    • 感谢您展示另一种方式。这种方法似乎很有希望。我会试一试的。
    【解决方案3】:

    也许你需要这样的东西:

    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;
      

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

    • 为 CDI 做一个扩展,以编程方式注册生产者
    • 或者为每个可能的 source 和 eventName 组合创建 producer 方法(我不认为这很好)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-26
      • 2011-12-15
      • 2016-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-20
      相关资源
      最近更新 更多