我们有一个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 **/ }
EnderecoController
@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例外的解释有些困难.
解决方法
那么经过很多的搜索和阅读,我们终于解决了.事实证明,webapp最初是为Java EE 6开发的,并且决定使用Java EE 7.嗯… Java EE 7中的某些东西是不同的.它以不同的方式处理托管的bean范围.首先,JavaView 7文档中甚至没有提到@ViewScoped注释(有一个新的@FlowScoped,但是我们仍在阅读).我们将日志级别提高到FINEST,并通过无休止的细节来了解发生了什么.
为了使它像今天一样使用代码,我们必须了解CDI实现的一个关键区别.直到Java EE 6,CDI将扫描所有软件包,并且容器将考虑所有的bean.这种行为显然是用Java EE 7改变的,只有注册具有特定范围的类才被认为是管理bean.换句话说,@Named注释需要附带一个范围注释(@RequestScoped,@SessionScoped,@DependentScoped,@FlowScoped等).由于@ViewScoped不再是官方范围列表的一部分,因此当CDI启动时,EnderecoController类不会成为托管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>
使用全部发现模式会导致CDI在扫描受管Bean时包括所有类,包括没有CDI范围注释的类.我们现在正在进一步了解新的范围管理更好地适应Java EE 7标准的代码.
我仍然觉得奇怪的是,原始代码在一个完整的glassfish安装中工作,但不在maven-embedded-glassfish-plugin内.
我个人对Java EE / CDI的咆哮
此外,我想对WELD-001408不满足的依赖堆栈跟踪给出的荒谬广泛的描述进行明确的评论.该消息仅仅意味着CDI无法提供依赖注入.没有关于什么类型的错误导致未被创建的注入的bean的细节.甚至不是“抱歉,找不到要实例化的bean”.
由于各种原因,可能会发生不满意的依赖.在尝试实例化依赖关系时发生的任何异常都被隐藏在日志文件之外.您可能会花一个小时,直到您意识到您的bean的构造函数抛出NullPointerException.这个例外包装废话是为什么在Google上搜索此错误消息导致由于不同原因导致相同错误的人的海洋的原因.
我希望他们改进错误处理,提高异常消息,以便我们更好地了解为什么某些特定依赖不能满足.