CDI 范围和生产商

CDI Scope and Producers

有人可以解释一下 CDI Scope 注释在生产者方面的作用吗?他们似乎没有完成任何事情。

@Produces
public Thing thingMaker() {
    System.out.println("Making thingmaker");
    return new ThingBean("thingMaker");
}

@Produces
@RequestScoped
public Thing thingMakerReq() {
    System.out.println("Making thingmakerReq");
    return new ThingBean("thingMakerReq");
}

这些自然会在启动时给出这个(省略的)错误。

WELD-001409: Ambiguous dependencies for type Thing. Possible dependencies:

  • Producer Method [Thing] with qualifiers [@Any @Default] declared as [[BackedAnnotatedMethod] @Produces public pkg.test.ThingProducer.thingMaker()],
  • Producer Method [Thing] with qualifiers [@Any @Default] declared as [[BackedAnnotatedMethod] @Produces @RequestScoped public pkg.test.ThingProducer.thingMakerReq()]

因此,即使 `RequestScoped 被标记为生产者方法的一部分,它们也不是限定符。

所以我只是不确定他们在生产者方法方面的作用是什么。

生产者方法上的

CDI scope 注释定义了 produced bean 的范围;所以:

@Produces // produces Thing in the default scope, i.e. @Dependent
public Thing thingMaker() {
    System.out.println("Making thingmaker");
    return new ThingBean("thingMaker");
}

@Produces // produces Thing in request scope
@RequestScoped
public Thing thingMakerReq() {
    System.out.println("Making thingmakerReq");
    return new ThingBean("thingMakerReq");
}

如果只有这两种方法,他们是可以和平共处的。当你想注入一个 Thing 时,问题就出现了,如:

    @Inject
    private Thing thing;

CDI搜索其命名空间,发现不止一个bean可以满足这个注入点;不知道该怎么做,它失败了(在 Weld 是 CDI 实现的特定情况下使用 WELD-001409)。例如,以下内容是完全合法的:

    @Inject
    private Instance<Thing> things;

Instance 可以为您提供满足注入点的 bean 集合,您可以选择其中任何一个来使用。

现在,限定符是另一回事,它与 CDI 如何找到满足注入点的 bean 有关。

首先,消除误解:范围注释不是限定符。您可以注意到在 CDI 的消息中,“with qualifiers [@Any @Default] declared as [[... @RequestScoped ...] ”。这也意味着您不能从注入点中的特定范围请求 bean。并且包含注入点的bean的范围对注入bean的选择也没有任何作用。范围是 bean 的实现细节:假设您有一个 @ApplicationScoped bean,然后在某个时候您意识到它需要请求级信息来实现某些功能。您可以更改它的范围,使用它的 beans 不应该在意,它们将继续工作而不会发生变化。

限定符是一种消除依赖关系歧义的方法,当类型不够时,就像你的情况一样。一个常见的例子是当有许多配置属性时,表示为字符串。假设一个 DB 用户名和密码,都是 String 类型:(警告:天真的例子,具有绑定属性的限定符会更合适,参见例如 Microprofile 配置)

    @Inject
    @DbUsername // this is the qualifier
    private String dbUsername;

    @Inject
    @DbPassword // this is the qualifier
    private String dbPassword;