Java依赖注入-在场景中可能基于注释的设置?

问题描述

我正在使用简单的JUnit测试和javax.inject-Annotations来研究Java中的依赖注入。

我有以下情形:有一个具有两个依赖项(SomeObjDepA和SomeObjDepB)的“顶级”类(SomeObject)。 SomeObjDepB也依赖于SomeObjDepA。并且这应该与SomeObject-instance中的SomeObjDepA实例相同。但是SomeObjDepA不能为Singleton,因为不同的SomeObj实例应具有SomeObjDepA(和SomeObjDepB)的不同实例。这就是我被困住的地方。

更清楚地说,这是一些没有任何配置的基本代码

public class SomeObject {

  @Inject
  private SomeObjDepA someObjDepA;

  @Inject
  private SomeObjDepB someObjDepB;

  public SomeObjDepA getSomeObjDepA() {
    return someObjDepA;
  }

  public SomeObjDepB getSomeObjDepB() {
    return someObjDepB;
  }
}
public class SomeObjDepA {

}
public class SomeObjDepB {

  @Inject
  private SomeObjDepA someObjDepA;

  public SomeObjDepA getSomeObjDepA() {
    return someObjDepA;
  }
}
public class DependencyInjectionTest {

  @Inject
  private Provider<SomeObject> someObjProvider;

  @Test
  public void instancestest() {
    final SomeObject someObjInst1 = this.someObjProvider.get();
    final SomeObject someObjInst2 = this.someObjProvider.get();

    Assertions.assertNotEquals(someObjInst1,someObjInst2);
    Assertions.assertNotEquals(someObjInst1.getSomeObjDepA(),someObjInst2.getSomeObjDepA());
    Assertions.assertNotEquals(someObjInst1.getSomeObjDepB(),someObjInst2.getSomeObjDepB());
    Assertions.assertEquals(someObjInst1.getSomeObjDepA(),someObjInst1.getSomeObjDepB().getSomeObjDepA());
    Assertions.assertEquals(someObjInst2.getSomeObjDepA(),someObjInst2.getSomeObjDepB().getSomeObjDepA());
  }
}

问题:如何设置依赖项注入来构建这样的场景?我正在寻找注释或基于Java的配置(如果可能)

我目前正在使用CDI 2.0(焊接3.1.5)和JUnit 5进行测试。我更喜欢使用CDI的解决方案,但是使用Spring,Guice等的任何其他解决方案都可以。

非常感谢

解决方法

根据您要查找的内容,您想使用作用域和/或限定符

您可以将范围视为寿命。如果您未指定范围(不在上方),则默认范围是“在需要时创建一个新的范围”,这称为依赖范围。 (这是因为被注入的物体的寿命 取决于容纳该物体的物体。)

正如@Glains指出的那样,@ApplicationScoped是指示bean应该在“应用程序范围”中的一种方式,该范围基本上是具有额外优点的单例范围。因此,您可以将其放在任何符合要求的类上,以表明其寿命应该是整个应用程序的寿命。

接下来,您要讨论如何区分给定对象的两个本来无法区分的事件,两者都可能是单例(SomeObjDepA)。 限定词可让您做到这一点。

比方说,您有一个producer method,它的颜色为“黄色” SomeObjDepA,另一个是红色的SomeObjDepA。要在CDI中执行此操作,您需要qualifier annotations来表示“红色”和“黄色”位。然后在生产现场应用它们。例如:

@ApplicationScoped // producer methods need to be "housed" in a bean
public class Host {

  @Produces
  @Red // you define this annotation following the spec's rules for qualifier annotations
  @ApplicationScoped // ...or whatever scope is called for
  public SomeDepA produceRedDepA() {
    return new SomeDepA();
  }

  @Produces
  @Yellow // you define this annotation following the spec's rules for qualifier annotations
  @ApplicationScoped // ...or whatever scope is called for
  public SomeDepA produceYellowDepA() {
    return new SomeDepA();
  }

}

在这里,我们有两种生产者方法,容器将适当地调用它们,并将“满足”其他位置的相关注入点。例如,在SomeObject中,您可能具有:

@Inject
@Red
private SomeDepA red;

@Inject
@Yellow
private SomeDepA yellow;