9

我们有一个 webapp,目前正在使用 Java EE 7、JSF 2.2 和 Glassfish 4.0 开发。有两个具有循环依赖关系的特定托管 bean。

UsuarioController

@Named
@SessionScoped
public class UsuarioController implements Serializable {

    /** snipet **/

    @Inject
    private EnderecoController enderecoController;

    /** snipet **/
}

Endereco控制器

@Named
@ViewScoped
public class EnderecoController {

    /** snipet **/

    @Inject
    private UsuarioController esuarioController;

    /** snipet **/
}

当 webapp 被打包并部署到正常的 glassfish 4.0 安装时,它工作正常。

但是,在开发过程中,我们使用maven-embedded-glassfish在 IDE 中进行本地测试。并且应用程序部署失败,并出现以下异常。

SEVERE: Exception while loading the app : CDI deployment failure:WELD-001408 Unsatisfied dependencies for type [EnderecoController] with qualifiers [@Default] at injection point [[BackedAnnotatedField] @Inject private net.jhm.exemplo.view.UsuarioController.enderecoController]
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [EnderecoController] with qualifiers [@Default] at injection point [[BackedAnnotatedField] @Inject private net.jhm.exemplo.view.UsuarioController.enderecoController]
    at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:403)
    at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:325)
    at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:177)
    at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:208)
    at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:519)
    at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:505)
    at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:480)
    at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:536)
    at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:216)
    at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:131)
    at org.glassfish.internal.data.ApplicationInfo.load(ApplicationInfo.java:328)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:493)
    at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:219)
    at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:491)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:527)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:523)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:356)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:522)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:546)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1423)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1500(CommandRunnerImpl.java:108)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1762)
    at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1674)
    at com.sun.enterprise.admin.cli.embeddable.DeployerImpl.deploy(DeployerImpl.java:133)
    at com.sun.enterprise.admin.cli.embeddable.DeployerImpl.deploy(DeployerImpl.java:109)
    at org.glassfish.maven.PluginUtil.doDeploy(PluginUtil.java:108)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.glassfish.maven.AbstractDeployMojo.doDeploy(AbstractDeployMojo.java:259)
    at org.glassfish.maven.DeployMojo.execute(DeployMojo.java:69)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:320)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)

Aug 07, 2013 12:22:31 PM PluginUtil doDeploy
INFO: Deployed null

任何人都可以帮助我们的开发环境解决这个问题吗?有几个人更喜欢嵌入式 glassfish 插件,而不是用于本地开发的完整服务器。

似乎特别是与 maven-embedded-glassfish 相关的依赖项/类路径问题,但我们不知道从哪里开始。在 Google 周围找到 CDI WELD-NNNNNN 异常的解释有点困难。

4

1 回答 1

24

好吧,经过大量搜索和阅读,我们终于解决了它。事实证明,该 webapp 最初是为 Java EE 6 开发的,并且在此过程中决定使用 Java EE 7。嗯...在 Java EE 7 中有些不同。它以不同的方式处理托管 bean 范围。一方面,@ViewScopedJava EE 7 文档中甚至都没有提到该注释(有一个新的@FlowScoped,但我们仍在阅读它)。我们将日志级别提高到 FINEST,并通过无穷无尽的细节来了解发生了什么。

为了让它与现在的代码一起工作,我们必须了解 CDI 实现的一个关键区别。在 Java EE 6 之前,CDI 会扫描所有包,并且容器会考虑所有 bean。这种行为显然在 Java EE 7 中发生了变化,在这种方式下,只有使用特定范围注释的类才被考虑成为托管 bean。换句话说,@Named注释需要伴随一个范围注释(@RequestScoped@SessionScoped@DependentScoped@FlowScoped等)。由于@ViewScoped不再是官方范围列表的一部分,因此EnderecoController当 CDI 启动时,该类不会成为托管 bean。尝试将实例注入UsuarioController会导致通用 WELD 依赖异常,因为从未创建过该 bean 的实例。

为了使事情在向后可移植性中起作用,我们必须将WEB-IBNF/beans.xml文件更改为将属性更改bean-discovery-mode="annotated"bean-discovery-mode="all".

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="all">
</beans>

使用all发现模式会导致 CDI 在扫描托管 bean 时包括所有要考虑的类,包括那些没有 CDI 范围注释的类。我们现在正在努力更好地理解新的范围管理,以使代码适应 Java EE 7 标准。

我仍然觉得奇怪的是,原始代码在完整的 glassfish 安装中有效,但在 maven-embedded-glassfish-plugin 中无效。

我个人对 Java EE/CDI 的吐槽

另外,我想明确评论WELD-001408 Unsatisfied 依赖堆栈跟踪给出的荒谬广泛的描述。该消息仅意味着 CDI 无法提供依赖注入。没有关于什么类型的错误导致注入的 bean 首先没有被创建的详细信息。甚至没有“抱歉,无法找到要实例化的 bean”。

由于各种原因,可能会出现不满足的依赖关系。尝试实例化依赖项时发生的任何异常都会隐藏在日志文件之外。您可能会花费一个小时,直到您意识到您的 bean 的构造函数正在抛出一个NullPointerException. 这种包装废话的异常是为什么在 Google 上搜索此错误消息会导致大量人由于不同原因而出现相同错误的原因。

我希望他们改进错误处理,引发异常消息,以便我们能够更好地理解为什么某些特定的依赖关系不能被满足。

于 2013-08-07T19:31:04.130 回答