将参数传递给@Inject豆实例

2022-09-03 01:51:05

我使用CDI作为注入框架,但我在其使用中发现了一些限制,这是其中之一。我正在尝试使用运行时值初始化Bean实例的创建。例:

@RequestScoped
public class MyNumber {
   int number;

   public MyNumber(int number) {
      this.number = number;
   }

   public String toString() {
      return "Your number is: " + number;
   }
}

public class UseNumber {
   @Inject
   Instance<MyNumber> number;

   public void doStuff() {
      int a = 8;
      MyNumber mN = number.select(a).get(); // ?? - Obviously this does not work.

      System.out.print(mN); // Should print: "Your number is: 8"
   }
}

请注意,“a”在示例中是一个常量,但实际上它是一个变量;我澄清了这一点,所以你不会发布一个带有a的答案来注入值,然后在 的构造函数中注入。@ProducerMyNumber

现在,有人知道我该怎么做吗?


答案 1

我不确定您要做什么,但据我所知,您希望使用注入点注释中的数据或在运行时通过编程查找来初始化Bean。您可以通过在 Bean 中使用元数据来执行此操作(唯一的约束是将 Bean 置于依赖作用域中)InjectionPoint

你可以做这样的事情。

首先创建一个具有非约束值的限定符。

@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
@Documented
public @interface Initialized {

    @Nonbinding int value() default 0; // int value will be store here 
}

您必须在 Bean 上添加此限定符,并在创建时进行分析。InjectionPoint

@Initialized
public class MyNumber {
   int number;

   private int extractValue(InjectionPoint ip) {
    for (Annotation annotation : ip.getQualifiers()) {
        if (annotation.annotationType().equals(Initialized.class))
            return ((Initialized) annotation).value();
    }
    throw new IllegalStateException("No @Initialized on InjectionPoint");
  }

   @Inject
   public MyNumber(InjectionPoint ip) {
      this.number = extractValue(ip);
   }

   public String toString() {
      return "Your number is: " + number;
   }
}

您现在可以注入一个初始化的数字,如下所示:

@Inject
@Initialized(8)
MyNumber number;

如果要在运行时确定初始化值,则必须使用编程查找:

首先为“@Initialized”创建批注文本

public class InitializedLiteral extends AnnotationLiteral<Initialized> implements Initialized {

    private int value;

    public InitializedLiteral(int value) {
        this.value = value;
    }

    @Override
    public int value() {
        return value;
    }
}

然后,您可以使用 来创建您的 Bean。Instance

public class ConsumingBean {

    @Inject
    @Any
    Instance<MyNumber> myNumberInstance;

    public MyNumber getMyNumberBeanFor(int value) {
     return myNumberInstance.select(new InitializedLiteral(value)).get();
    }
    ...
}

请记住,这仅在 相关范围内有效,这是有道理的,因为这是在每次注入时更改初始化值的唯一方法。MyNumber


答案 2

根据规范,没有办法让一个豆子有一个不简单的,“不注入”的构造函数(3.1。受管豆 3.9.Bean 构造函数 )。

因此,设置参数的方法是为它们设置method(),使它们成为bean中的@Inject字段,或者用注释@Inject注释构造函数,并使构造函数的参数可注入(5.5.1。使用 Bean 构造函数进行注入 )

我希望,我回答了这个问题。


推荐