【问题标题】:Inject several of the Same CDI bean into a class?将几个相同的CDI bean注入一个类?
【发布时间】:2021-12-05 20:57:42
【问题描述】:

目前,我的 CDI bean 注入一次就能完成所有工作,但我需要大约 6 到 10 个单独的实例(?),具体取决于我的输入。 (理想情况下,我希望能够根据需要注入动态数量的相同 CDI bean。)

不幸的是,我需要注入 bean,因为该类依赖于另一个 CDI bean。 (见下文2.CDI bean类)

  1. 客户端类
@ApplicationScoped
public class Clients {
   Publisher pub;
   Subscriber sub;
   @Inject
   ListenerBean listener;

   public void init(){
      pub = new Publisher();
      sub = new Subscriber(listener);
   }
}
  1. CDI bean 类
@Dependent
public class ListenerBean{
   @Inject
   private eventHandler h;

   public void onMessage(Msg msg){
      h.doesSomething();
   }
}

我正在寻找的功能,但不确定那里有什么可用的。我还没有找到任何人想要完成同样的事情。

for(Subscriber s: listOfSubscribers){
   @Inject
   ListenerBean l;
   s = new Subscriber(l);
}

// The only thing I can do right now is
@Inject
ListenerBean listener1;
@Inject
ListenerBean listener2;
@Inject
ListenerBean listener3;
@Inject
ListenerBean listener4;

编辑:听众确实需要是可识别的。 (在注入后调用 setter。)可能不是最佳实践,但不确定如何实现这一点-

  • 监听器将监听不同的主题(由各自的消费者声明)
  • 每个听众都必须根据主题处理他们的消息
@Inject
ListenerBean listener1;
listener1.setTopic("TopicA");

【问题讨论】:

  • 不能注入List<ListenerBean>吗?
  • 我相信,如果ListenerBean@Dependent 并且您注入Instance<ListenerBean> listenerInstance,那么每次您执行listenerInstance.get() 时都会得到一个新副本。确保在处理完这些实例后将其处理掉。
  • 这听起来像是一个使用标准 Event@Observes 代替的经典示例。
  • @chrylis-cautiouslyoptimistic- 这不是一回事...见post 4009388
  • @NikosParaskevopoulos 谢谢!我会试试这个

标签: java cdi javabeans java-ee-8


【解决方案1】:

如果您需要注入 @Dependent 范围 bean 的多个 不同 实例,您可以通过 programmatic lookup 来实现 - 换句话说,通过 Instance<T>

通过Instance@Dependent bean 的每个bean 解析都将导致创建一个新的bean 实例。以下代码说明了这一点:

@Inject Instance<ListenerBean> instance;

public void createMultipleBeanInstances() {
  // bean1 and bean2 are two different instances because the bean is @Dependent
  // you can OFC do this in a cycle and generate as many as you like
  ListenerBean bean1 = instance.get(); 
  ListenerBean bean2 = instance.get();
}

请注意,您通过编程查找创建的依赖 bean 的生命周期绑定到 Instance 对象,这意味着只要 Instance 存在,它们就会存在。假设您将@Inject Instance 注入到 bean 中,它将与注入它的 bean 一起被销毁。

【讨论】:

  • 非常感谢,也谢谢你的例子!!是的,我想要像你描述的那样注入 不同的 实例,我会看看这是否适合我
  • 这部分对我有用。但是,如果我希望 ListenerBean 单独注入——该类应该是@Dependent 作用域,对吗?我编辑了我的原始帖子以包含我错过的细节。 -- 我需要在 ListenerBeans 中设置一个值。但我不确定 @Dependent 是否是 Listener 的正确范围
  • 不确定我是否理解您的问题。它们是可识别的,您仍然可以使用bean1.setTopic("someTopic")。至于范围,只有您可以知道哪个范围适合您的场景。但是,如果 Listener 是指 CDI 观察者,请注意 @Dependent 范围意味着将创建一个 单独的 bean 实例来观察触发的事件,然后将其销毁。
  • 实际上,这是一个单独的问题。这个解决方案,奏效了!!非常感谢:)
【解决方案2】:

我的评论后的解释。不过我可能误解了你的问题。

首先,您的代码看起来基本上类似于多播器的实现:您注入了几个对象,这些对象都实现了一个通用接口来调用相同的方法。

我认为,在尝试注入各种接收器对象时,您基本上遇到了一个 XY 问题:发射器是否真的需要知道接收器,或者事件到达就足够了目标?

如果我的假设是正确的,即您的发射器并不真正需要知道订阅者,您可以简单地使用Event 标准机制:

首先,定义一个消息(可以携带附加信息,但这不是特别需要,只需要一个类):

public class MyMessage {
     // if needed, add some fields
}

然后,在您的发射器中,注入相应的事件类型,并使用它来触发消息:

@Inject
private Event<MyMessage> myEvent;  // note: type is message, not the bean

...

myEvent.fire(new MyMessage()); // to broadcast the message to everyone who is interested

在您的订阅者中,只需@Observe 消息:

public void theMethodWeWantCalled(@Observes MyMessage messageObject) {
    // do things here
}

就是这样:无需耦合发射器和订阅器。

【讨论】:

  • 谢谢,这更有意义。不幸的是,我认为发射器确实需要知道接收器?因为我仍然需要他们设置一个字段:(请参阅我刚刚在我的帖子上所做的编辑。
猜你喜欢
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 2015-04-15
  • 1970-01-01
  • 2015-08-28
  • 1970-01-01
  • 1970-01-01
  • 2014-06-02
相关资源
最近更新 更多