Glassfish 4.1 CDI WELD-001409:不明确的依赖关系

Glassfish 4.1 CDI WELD-001409: Ambiguous dependencies

我正在 Glassfish 4.1 中部署的项目中工作。依赖注入是使用 CDI 进行的,我在尝试部署应用程序时遇到了问题。我得到的错误如下(通常我在代码中“翻译”我的 classes 的名称,所以整个 post 使用相同的语言,我现在不会这样做我可以 copy/paste 并避免一些翻译打字错误):

服务器日志

org.glassfish.deployment.common.DeploymentException: CDI deployment failure:Exception List with 3 exceptions:
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type GestorUsuarios with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private ar.edu.unt.sigea.servicios.impl.GestorPersonasImpl.gestorUsuarios
  at ar.edu.unt.sigea.servicios.impl.GestorPersonasImpl.gestorUsuarios(GestorPersonasImpl.java:0)
  Possible dependencies: 
  - Session bean [class ar.edu.unt.sigea.servicios.impl.GestorUsuariosImpl with qualifiers [@Any @Default]; local interfaces are [GestorUsuarios],
  - Managed Bean [class ar.edu.unt.sigea.servicios.impl.GestorUsuariosImpl] with qualifiers [@Any @Default]
        ...[Stack trace]...

Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type RepositorioMenu with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private ar.edu.unt.sigea.servicios.impl.GestorUsuariosImpl.repositorioMenu
  at ar.edu.unt.sigea.servicios.impl.GestorUsuariosImpl.repositorioMenu(GestorUsuariosImpl.java:0)
  Possible dependencies: 
  - Managed Bean [class ar.edu.unt.sigea.repositorio.RepositorioMenu] with qualifiers [@Any @Default],
  - Session bean [class ar.edu.unt.sigea.repositorio.RepositorioMenu with qualifiers [@Any @Default]; local interfaces are [RepositorioMenu]
        ...[Stack trace]...

Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type RepositorioOperacion with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject ar.edu.unt.sigea.repositorio.RepositorioMenu.repositorioOperacion
  at ar.edu.unt.sigea.repositorio.RepositorioMenu.repositorioOperacion(RepositorioMenu.java:0)
  Possible dependencies: 
  - Managed Bean [class ar.edu.unt.sigea.repositorio.RepositorioOperacion] with qualifiers [@Any @Default],
  - Session bean [class ar.edu.unt.sigea.repositorio.RepositorioOperacion with qualifiers [@Any @Default]; local interfaces are [RepositorioOperacion]

(顺便说一下,我不知道为什么它说 3 exceptions 并且都显示为 Exception 0

参与classes

@Stateless
public class GestorPersonasImpl implements GestorPersonas {

    @Inject
    private GestorUsuarios gestorUsuarios;

    public GestorUsuarios getGestorUsuarios() {return gestorUsuarios;}

    public void setGestorUsuarios(GestorUsuarios gestorUsuarios) {
        this.gestorUsuarios = gestorUsuarios;
    }
    // Other fields and methods
}

@Stateless
public class GestorUsuariosImpl implements GestorUsuarios {

    @Inject
    private RepositorioMenu repositorioMenu;

    public RepositorioMenu getRepositorioMenu() {return repositorioMenu;}

    public void setRepositorioMenu(RepositorioMenu repositorioMenu) {
        this.repositorioMenu = repositorioMenu;
    }
    // Other fields and methods
}

@Stateless
@LocalBean
public class RepositorioMenu extends RepositorioGenerico<Menu> {

    @Inject
    private RepositorioOperacion repositorioOperacion;

    public RepositorioOperacion getRepositorioOperacion() {return repositorioOperacion;}

    public void setRepositorioOperacion(RepositorioOperacion repositorioOperacion) {
        this.repositorioOperacion = repositorioOperacion;
    }
    // Other fields and methods
}

@Dependent
@Stateless
@LocalBean
public class RepositorioOperacion extends RepositorioGenerico<Operacion> {
    // This class doesn't have injection points
    // just put it here for the reference made in the error message
}

父 class RepositorioGenerico<Menu> 只是一个 class,具有一些与数据库交互的通用方法,Menu 是一个实体 class。接口如下:

@Local
public interface GestorPersonas {
    // methods definitions, implemented by GestorPersonasImpl
}

@Local
public interface GestorUsuarios {
    // methods definitions, implemented by GestorUsuariosImpl
}

每个注入点我只有一个注入class所以我不明白为什么注入失败。我不知道是否需要有关我的代码的更多详细信息,所以问我,我会编辑 post;我只写我认为需要的部分。

我看过另一个 post,但那里使用了 @Produces 注释,据我所知,在这种情况下我不需要它。

感谢任何帮助或指导。预先感谢您的回答

编辑 1

我在 Antonio Goncalves in the Java Magazine 的一篇文章中读到,CDI 是通过属性(甚至私有)、setter 方法或构造函数创建的。考虑到这一点,我为每个注入的 属性 删除了 getter 和 setters 并解决了对这些属性的默认(包)的访问。

用于注入属性的 getter/setter 方法仅用于在我的单元测试中手动设置依赖项,因此在生产中不需要它们。

所有这些更改后,错误仍然存​​在...

更多信息

根据 Java EE 7 official documentation,我的 bean 符合 CDI Managed Bean 定义,除了点

It is not annotated with an EJB component-defining annotation or declared as an EJB bean class in ejb-jar.xml.

根据 javax.ejb javadoc EJB component-defining annotation is one of the followings: @MessageDriven, @Stateful, @Stateless or @Singleton. But I've seen other projects with CDI working with EJB (e.g., @Stateless beans being injected somewhere else). On the other hand, I've been reading Beginning Java EE 7 by Antonio Goncalves 并说(第 2 章 - 上下文和依赖注入):

Anatomy of a CDI Bean

According to the CDI 1.1 specification, the container treats any class that satisfies the following conditions as a CDI Bean:

  • It is not a non-static inner class,
  • It is a concrete class, or is annotated @Decorator, and
  • It has a default constructor with no parameters, or it declares a constructor annotated @Inject.

Then a bean can have an optional scope, an optional EL name, a set of interceptor bindings, and an optional life-cycle management.

我的 bean 符合该定义。我检查了 Weld Documentation and in chapter 2 带来的 CDI bean 的定义,它更接近第一个定义(来自 Java EE 文档)。问题是,正如我所说,我已经看到其他项目使用 EJB Managed Beans(@Stateless 或其他一些)进行依赖注入。

总而言之,我不知道该相信谁。有人可以阐明这件事吗?

尝试失败

注意:在这次尝试之后,我在不同的地方遇到了同样的问题,所以服务器日志和涉及的classes与上面所述有所不同,检查差异。

首先,根据直觉,我为需要注入到其他地方的 bean 添加了接口。

其次,我将 Glassfish Server 从 4.1 更新到 4.1.1。这个捆绑了 WELD-2.2.13.Final CDI 实现(根据服务器日志消息 INFO: WELD-000900: 2.2.13 (Final))。

最后我尝试部署我的项目,但经过一些更改后错误仍然存​​在。在显示更改之前,让我说它从未引起我的注意,但在部署时,JNDI 为我的 bean 生成了 2 个名称,如我尝试部署应用程序时抛出的以下日志消息中所述:

INFO:   Portable JNDI names for EJB RepositorioUsuarioImpl: [java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/RepositorioUsuarioImpl, java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/RepositorioUsuarioImpl!ar.edu.unt.sigea.repositorio.RepositorioUsuario]
INFO:   Portable JNDI names for EJB RepositorioAlumnoImpl: [java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/RepositorioAlumnoImpl, java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/RepositorioAlumnoImpl!ar.edu.unt.sigea.repositorio.RepositorioAlumno]
INFO:   Portable JNDI names for EJB RepositorioMenuImpl: [java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/RepositorioMenuImpl, java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/RepositorioMenuImpl!ar.edu.unt.sigea.repositorio.RepositorioMenu]
INFO:   Portable JNDI names for EJB GestorUsuariosImpl: [java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/GestorUsuariosImpl, java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/GestorUsuariosImpl!ar.edu.unt.sigea.servicios.GestorUsuarios]
INFO:   Portable JNDI names for EJB GestorPersonasImpl: [java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/GestorPersonasImpl!ar.edu.unt.sigea.servicios.GestorPersonas, java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/GestorPersonasImpl]
INFO:   Portable JNDI names for EJB RepositorioPersonaImpl: [java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/RepositorioPersonaImpl, java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/RepositorioPersonaImpl!ar.edu.unt.sigea.repositorio.RepositorioPersona]
INFO:   Portable JNDI names for EJB RepositorioOperacionImpl: [java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/RepositorioOperacionImpl!ar.edu.unt.sigea.repositorio.RepositorioOperacion, java:global/sigea-ear-0.8-SNAPSHOT/sigea-model-0.8-SNAPSHOT/RepositorioOperacionImpl]

我不知道这是否会导致注入点错误,但听起来很可疑(而且我不知道如何更改它)。它也出现在第一次尝试中,但正如我所说,它从未引起我的注意。现在日志和 classes

服务器日志

Fatal:   Exception during lifecycle processing
org. glassfish.deployment.common.DeploymentException: CDI deployment failure:Exception List with 2 exceptions:
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type GestorPersonas with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject ar.edu.unt.sigea.inicio.RegistroBean.gestorPersonas
  at ar.edu.unt.sigea.inicio.RegistroBean.gestorPersonas(RegistroBean.java:0)
  Possible dependencies: 
  - Session bean [class ar.edu.unt.sigea.servicios.impl.GestorPersonasImpl with qualifiers [@Any @Default]; local interfaces are [GestorPersonas],
  - Managed Bean [class ar.edu.unt.sigea.servicios.impl.GestorPersonasImpl] with qualifiers [@Any @Default]
    ...[Stack trace]...

Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type GestorUsuarios with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject ar.edu.unt.sigea.inicio.SesionUsuarioBean.gestorUsuarios
  at ar.edu.unt.sigea.inicio.SesionUsuarioBean.gestorUsuarios(SesionUsuarioBean.java:0)
  Possible dependencies: 
  - Session bean [class ar.edu.unt.sigea.servicios.impl.GestorUsuariosImpl with qualifiers [@Any @Default]; local interfaces are [GestorUsuarios],
  - Managed Bean [class ar.edu.unt.sigea.servicios.impl.GestorUsuariosImpl] with qualifiers [@Any @Default]
    ...[Stack trace]...

参与classes

@Named(value = "registroBean")
@ViewScoped
public class RegistroBean implements Serializable {

    private static final long serialVersionUID = 2181909526300424451L;

    @Inject
    GestorPersonas gestorPersonas;

    // fields, methods, etc
}

@Named(value = "sesionUsuarioBean")
@SessionScoped
public class SesionUsuarioBean implements Serializable {

    private static final long serialVersionUID = 2938631472102116238L;

    @Inject
    GestorUsuarios gestorUsuarios;

    // fields, methods, etc
}

注入的字段显示在主要部分中。

感谢您能为我提供有关此新信息的任何帮助。如果您需要有关该应用程序的更多信息,请告诉我。

提前感谢您的回答。

在互联网颠倒了 2 周后,我终于尝试在 Wildfly 10.0.0 服务器上部署,现在我的应用程序部署没有问题。所以我必须得出结论,这是 Glassfish 上的错误。 Pitty,因为我使用的是最新版本 (4.1.1),它是 CDI 发现的基本(我认为)。希望 Payara 能解决这个问题,但我现在不会尝试。

我必须说:如果一个服务器被认为是 "Java EE 7 compliant",那么它不应该被发布带有这种错误。

如果有人知道论坛或知道不同服务器的一些基准测试结果,请将其评论出来。 Glassfish 真丢脸

我在 Payara 中遇到了同样的问题,我通过删除 EAR 模块中的依赖项解决了这个问题。

所以之前,我的 EAR 模块依赖于 EJB 模块, 而且我的 war 模块依赖于 EJB 模块。 所以在构建时,我认为它们都生成了 类 两次并最终混淆了 CDI。 所以去除 EAR 对 EJB 模块的依赖问题

有点摸不着头脑,但我遇到了一些类似的问题。我的解决方案是禁用 Glassfish 的隐式 cdi 功能(在 4.x 中默认启用)。

部署时:

asadmin deploy --property implicitCdiEnabled=false  ...

或者作为服务器范围的配置:

asadmin set configs.config.server-config.cdi-service.enable-implicit-cdi=false

话又说回来,停止使用 Glassfish 并改用 Wildfly 之类的东西似乎是正确的方法(开始使用 Jetty 而不是我自己..)