【问题标题】:How to create instances on the fly in CDI如何在 CDI 中动态创建实例
【发布时间】:2013-02-10 15:17:03
【问题描述】:

假设我有一个 Car 课程。在我的代码中,我想创建 10 辆汽车。 Car 类有一些 @Inject 带注释的依赖项。

最好的方法是什么?

CDI 有一个Provider 接口,我可以用它来创建汽车:

@Inject Provider<Car> carProvider;
public void businessMethod(){
    Car car = carProvider.get();
}

不幸的是,如果我没有 CarFactory 有一个带有 @Produces 注释的方法来创建汽车,那么这不起作用。尽管它反映了现实世界,没有工厂我就无法制造汽车,但我宁愿不为所有东西都写工厂。我只希望 CDI 容器像其​​他 bean 一样创建我的汽车。

你建议我如何创建这些汽车?

【问题讨论】:

    标签: java java-ee-6 cdi


    【解决方案1】:

    您可以在 @Produces 注释中使用限定符:

    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
    public @interface MyCars {
    }
    

    样本生产者方法:

    @Produces
    @MyCars
    public Car getNewCar(@New Car car){
        return car;
    }
    

    用法:

    @Inject
    @MyCars
    private Provider<Car> carProvider;
    

    【讨论】:

    • '@New 在 CDI 1.1 中被弃用,而不是 @Dependent bean。请参阅 CDI 1.1,第 3.14 节。
    • @MartinAndersson 我知道,但由于 CDI 1.1 的答案尚未发布,所以答案转到 CDI 1.0(只是为了澄清这一点)
    【解决方案2】:

    只需使用javax.enterprise.inject.Instance 接口即可。

    像这样:

    public class Bean {
    
        private Instance<Car> carInstances;
    
        @Inject
        Bean(@Any Instance<Car> carInstances){
            this.carInstances = carInstances;
        }
    
        public void use(){
            Car newCar = carInstances.get();
            // Do stuff with car ...
        }
    
    }
    

    【讨论】:

    • 这实际上是我最终使用的。您能否修复您的示例,构造函数参数与类属性的类型不同:Car vs UIModule。另外我认为注入应该是@New而不是@Any的注释。 use() 方法的一个更好的例子是展示如何获得 Car 的实例。例如carInstances.get()
    • @New 在 CDI 1.1 中被弃用,优先于 @Dependent bean。参见 CDI 1.1,第 3.14 节。我真的不明白使用提供程序有什么问题,我。例如,CDI.current().select(Car.class).get() ?
    • @MartinAndersson 最初的问题是我必须创建一个工厂来使用提供程序。您在评论中提供的示例对我来说是全新的。也许您可以从中创建答案?
    【解决方案3】:

    我最喜欢的程序化查找模型是使用CDI.current().select().get()

    证明here

    servlet 依赖于两个 CDI bean,一个是请求范围,另一个是应用范围:

    private final RequestScopedBean requestScoped
                = CDI.current().select(RequestScopedBean.class).get();
    
    private final ApplicationScopedBean applicationScoped
                = CDI.current().select(ApplicationScopedBean.class).get();
    

    使用这个servlet的测试类可以在here找到。

    检查代码,您会发现该代码与使用@Inject MyBean myBean; 得到的代码完全等效。

    【讨论】:

      【解决方案4】:

      另一种方法是简单地不给 Car 任何 CDI 范围,这使其依赖,每次注入时您都会获得一个新实例,并且这些实例在包含实例被销毁之前不会被销毁。

      【讨论】:

      • 范围不用担心,据我了解,他希望有一个注入的生产者,而不必实现特定的生产者类。你是对的,所有注入的 cdi-beans 都变成了@dependent,但这不是 palto 所说的
      • “每次注入一个新实例”?如何“每次”注入受抚养人?注射只发生一次。代理的。如果注入了 @Dependent bean 或代理,则对该代理的每次调用都将始终路由到同一个支持 bean。
      • 它注入代理一次,是的,但是如果该代理解析为依赖范围的 bean,那么在请求注入的每个新 bean 实例上都会创建新的依赖范围 bean。注入的bean变得依赖于其他的生命周期。
      猜你喜欢
      • 2016-08-05
      • 1970-01-01
      • 2014-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-08
      相关资源
      最近更新 更多