【问题标题】:CDI - Bean name is ambiguousCDI - Bean 名称不明确
【发布时间】:2018-10-03 22:40:04
【问题描述】:

我已经定义了两个 Bean:

@Named("mysql")
public MySqlLogService extends AbstractLogService { ... }

@Named("mysql")
public MySqlConcurrencyService implements ConcurrencyService { ... }

我认为Named 限定符在某种程度上与 Bean 的类型相关,但是 Weld 返回:

Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001414: Bean name is ambiguous. Name mysql resolves to beans: 
  - Managed Bean [class my.package.MySqlConcurrencyService] with qualifiers [@Default @Named @Any],
  - Managed Bean [class my.other.package.MySqlLogService] with qualifiers [@Default @Named @Any]

为什么?限定符的范围是什么?

【问题讨论】:

    标签: java cdi


    【解决方案1】:

    无论类型如何,两个启用的 bean 都不能具有相同的 bean 名称(通过 @Named)。

    既然是 CDI,那我们看看 CDI 规范怎么样? 让我们从2.6. Bean names 开始,它声明:

    ...当在非类型安全环境(如统一表达式语言)中使用时,具有名称的 bean 可以通过其名称来引用....

    因此,您可以在不引用其类型的情况下使用该 bean。因此,需要能够将 bean 名称解析为一个特定的 bean。例如,当您从 JSF 页面使用 EL 时。

    再往前一点,上面写着:

    根据Ambiguous names 中定义的限制,多个bean 可以共享同一个bean 名称。

    这允许您真正“破坏”名称的唯一性,只要您可以保证在类型安全解析结束时,只会找到一个具有该给定名称的 bean。

    确保您的 bean 具有唯一的名称并且它可以工作。 如果它只是您所追求的限定词,那么使用 @Named 会带来您可能不需要的开销。只需创建自己的限定符并从那里开始。

    【讨论】:

    • 谢谢,一如既往。
    【解决方案2】:

    您似乎混淆了 CDI 注释。 @Named("my_custom_name") 注解用于显式引用该类/实现,例如:

    @Inject
    @Named("my_custom_name")
    ConcurrencyService service;
    

    如果您没有在 @Named 中定义自定义名称,那么默认情况下它会选择类名称,因此您不会遇到该错误。 在你的例子中:

    @Named
    MySqlLogService
    

    将被称为mySqlLogService

    @Named
    MySqlConcurrencyService
    

    将被称为mySqlConcurrencyService,但我仍然不明白你想要实现的目标。

    范围不是用@Named 定义的,而是使用:

    @RequestScoped
    @SessionScoped
    @ApplicationScoped
    @ConversationScoped
    

    更多信息here,这里有2个例子iii

    对于范围检查 oracle 的 page

    也是一个很好的博客,解释了Qualifiers

    【讨论】:

    • 这两个 bean 由 instance.select() 生成,传递一个 NamedLiteral,具有来自属性文件(mysql、SQL 服务器等)的字符串参数
    • 我想知道的是,如果类型层次结构不同,为什么名称会发生​​冲突。
    • 好吧,找不到与该问题相关的任何文档,但是如果您深入搜索一下,在 jboss 模块内部,有(可能)一个包含 bean 定义的映射,实际的 是您提供的名称,因此您会收到此异常
    • 是的,我已经调试过 Weld。无法理解,我以为在实现多次 SAME 接口时要指定限定符
    • 相同的接口,这是正确的,但显然名称将用作从 Bean Map/Cache 获取正确实例的键。如果你熟悉的话,这同样适用于 Spring DI。
    猜你喜欢
    • 2017-08-06
    • 2013-12-01
    • 2017-10-23
    • 1970-01-01
    • 2013-01-04
    • 2018-09-18
    • 1970-01-01
    • 2013-10-25
    • 2013-03-02
    相关资源
    最近更新 更多