【问题标题】:Pass Parameter to Instance of @Inject Bean将参数传递给@Inject Bean 的实例
【发布时间】:2014-05-24 13:17:39
【问题描述】:

我使用 CDI 作为注入框架,但我发现它的使用有一些限制,这就是其中之一。我正在尝试使用 runtime 值初始化 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”在示例中是一个常量,但实际上它是一个变量;我澄清了这一点,因此您不要使用@Producer 发布答案,然后将值注入MyNumber 的构造函数中。

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

【问题讨论】:

    标签: java cdi


    【解决方案1】:

    我不确定您要做什么,但据我了解,您希望使用注入点注释中的数据或在运行时通过编程查找来初始化您的 bean。您可以通过在 bean 中使用 InjectionPoint 元数据来做到这一点(唯一的限制是将您的 bean 置于依赖范围内)

    你可以这样做。

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

    @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;
        }
    }
    

    然后你可以使用Instance 来创建你的bean。

    public class ConsumingBean {
    
        @Inject
        @Any
        Instance<MyNumber> myNumberInstance;
    
        public MyNumber getMyNumberBeanFor(int value) {
         return myNumberInstance.select(new InitializedLiteral(value)).get();
        }
        ...
    }
    

    请记住,这仅在 MyNumber 处于依赖范围内时才有效,这是有意义的,因为这是在每次注入时更改初始化值的唯一方法。

    【讨论】:

    • @Antoine,您提供的示例运行良好,但是如果不需要传递参数,是否可以灵活地在从某些类注入 MyNumber 类时跳过使用 Initialized 注释?
    【解决方案2】:

    根据规范,没有办法让 bean 具有不简单的“不注入”构造函数( 3.1. Managed beans 3.9. Bean constructors )。

    因此,设置参数的方法是为它们设置setMethod(),使它们成为bean中的@Inject字段或使用@Inject注解对构造函数进行注解,并使构造函数的参数可注入( 5.5.1. Injection using the bean constructor )

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-29
      • 2021-10-26
      相关资源
      最近更新 更多