【问题标题】:Java CDI Invalid DependsOn dependencyJava CDI 无效的 DependsOn 依赖项
【发布时间】:2016-10-11 08:15:30
【问题描述】:

我正在尝试在应用程序启动时更新数据库中的一些内容。为了做到这一点,我创建了一个可以这样做的 A 类。

@Singleton
@Startup
@DependsOn({ "B", "C" })
public class A{
    @Inject B b;
    @Inject C c; 
    ...
}

B 是一个从数据库中读取一些配置值的类。乙:

@Singleton
@Startup
public class B {
     @PersistenceContext
     EntityManager em; 
     ...
}


C 是一种树结构,它使用 D 类和 E 类的数据来构造一个格式正确的树。
C:

@Singleton
@Startup
@DependsOn({ "D", "E" })
public class C{
     @Inject
     D d;
     @Inject
     E e; 
     ...
 }

D 和 E 是叶子单例,因为它们不依赖于其他单例;它们提供数据(从文件读取到数据库):
D:

@Singleton
@Startup
public class D { ... }


E:

@Singleton
@Startup
public class E { ... }

基于DependsOn annotation documentation,我假设 CDI 将为单例创建依赖关系图并按指定顺序初始化它们(B、D 和 E 将在 C 之前初始化,最后在 A 之前初始化)。但是,当我尝试部署应用程序时,我收到一个异常告诉我:
生命周期处理期间的异常 java.lang.RuntimeException:EJB ContentUpdater 的 DependsOn 依赖项“C”无效。

完整的堆栈跟踪:

java.lang.RuntimeException: Invalid DependsOn dependency 'C' for EJB A
at org.glassfish.ejb.deployment.util.EjbBundleValidator.checkDependsOn(EjbBundleValidator.java:602)
at org.glassfish.ejb.deployment.util.EjbBundleValidator.accept(EjbBundleValidator.java:300)
at org.glassfish.ejb.deployment.descriptor.EjbDescriptor.visit(EjbDescriptor.java:2823)
at org.glassfish.ejb.deployment.descriptor.EjbDescriptor.visit(EjbDescriptor.java:2811)
at org.glassfish.ejb.deployment.util.EjbBundleValidator.accept(EjbBundleValidator.java:115)
at com.sun.enterprise.deployment.BundleDescriptor.visit(BundleDescriptor.java:625)
at org.glassfish.ejb.deployment.descriptor.EjbBundleDescriptorImpl.visit(EjbBundleDescriptorImpl.java:757)
at com.sun.enterprise.deployment.util.ApplicationValidator.accept(ApplicationValidator.java:121)
at com.sun.enterprise.deployment.BundleDescriptor.visit(BundleDescriptor.java:625)
at com.sun.enterprise.deployment.archivist.ApplicationFactory.openArchive(ApplicationFactory.java:190)
at org.glassfish.javaee.core.deployment.DolProvider.processDOL(DolProvider.java:203)
at org.glassfish.javaee.core.deployment.DolProvider.load(DolProvider.java:227)
at org.glassfish.javaee.core.deployment.DolProvider.load(DolProvider.java:96)
at com.sun.enterprise.v3.server.ApplicationLifecycle.loadDeployer(ApplicationLifecycle.java:881)
at com.sun.enterprise.v3.server.ApplicationLifecycle.setupContainerInfos(ApplicationLifecycle.java:821)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:377)
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:539)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:535)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:360)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:534)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:565)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:557)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:360)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:556)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1464)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1300(CommandRunnerImpl.java:109)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1846)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1722)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:534)
at com.sun.enterprise.v3.admin.AdminAdapter.onMissingResource(AdminAdapter.java:224)
at org.glassfish.grizzly.http.server.StaticHttpHandlerBase.service(StaticHttpHandlerBase.java:189)
at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:201)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:175)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:561)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:565)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
at java.lang.Thread.run(Thread.java:745)

鉴于上述结构,有人知道为什么会发生此异常吗?

当我在 A 类的 @DependsOn 注释中省略 C 类时,我得到另一个异常,所以很遗憾这不是解决方案。 该应用程序部署在 GlassFish 4.1 上

【问题讨论】:

  • @DependsOn 是 EJB 注释,而不是 CDI。您要部署到什么容器,包括版本?您能否提供完整的堆栈跟踪,而不仅仅是一部分?
  • @JohnAment 我已经添加了完整的堆栈跟踪。容器是 GlassFish 4.1

标签: java cdi ejb-3.0 ejb-3.1


【解决方案1】:

我建议您重新考虑您的设计并只创建一个“StartUpController” 按您需要的顺序触发所有其他 ejb 上的 init 方法。

@Singleton
public class A {
    public void init() {}
}

@Singleton
public class B {
    public void init() {}
}

@Singleton
public class C {
    public void init() {}
}



@Startup
@Singleton
public class StartUpController {

    @Inject
    private A a;

    @Inject
    private B b;

    @Inject
    private C c;

    @PostConstruct
    protected void setup() {
        a.init();
        b.init();
        c.init();
    }

}

@DependsOn 并不是真正的“依赖控制”,这只是初始化顺序的控制,只有与 @PostConstruct 方法一起使用才有意义。(我在你身上看不到任何初始化方法例如)所以@DependsOn 不是必需的。您可以在没有此注释的情况下将 ejb 连接到链中,例如 thisthis 示例。

我无法准确回答为什么您的代码不起作用,也许这只是一个打字错误。例如,您在上面发布的代码中没有 C.class,而是使用 QuestionHandler.class,而且我在您的代码中没有看到任何 @PostConstruct 方法。另一个原因可能是 glashfish 配置我建议你在 Wildfly 服务器上尝试你的代码。

【讨论】:

  • 如果我理解正确,您是说基本上自己明确解决模块之间的依赖关系。这当然可以解决问题,但它不能回答为什么我的结构有问题
    是因为框架(EJB、CDI)无法处理我创建的层次结构吗?跨度>
  • @CharlesGreiner 您没有任何需要解决的“模块依赖项”。我更新了我的答案并添加了一些示例以便更好地理解。
  • 感谢您对答案的澄清。我已根据您的建议重组了我的代码,这解决了我的应用程序初始化问题。我确实在 A、B、D 和 E 类上有 @PostConstruct 注释方法,但在 C 上没有。这很可能是问题所在。
  • @CharlesGreiner 不客气,你能把问题标记为已解决吗 :)
  • 很抱歉迟到了这个答案。在我解决了这个问题后(在你的帮助下),我失去了对它的追踪。
【解决方案2】:

命名有误。 这里,具有名称“C”的预期bean不存在,而是单例bean名称是“questionHandler”,而且D是一个重复的类,而单例名称d和E.这是问题的错误,而不是必然原因的问题。

那么,如何避免这些“拼写”错误。

一种解决方案是使用静态字段来连接点。

答:

@Singleton(name = A.BEAN_NAME)
@Startup
@DependsOn({ B.BEAN_NAME, C.BEAN_NAME })
public class A {
    public static final BEAN_NAME = "A";

    @Inject B b;
    @Inject C c; 
    ...
}

乙:

@Singleton(name = B.BEAN_NAME)
@Startup
public class B {
    public static final BEAN_NAME = "B";

    @PersistenceContext
    EntityManager em; 
    ...
}

C:

@Singleton(name = QuestionHandler.BEAN_NAME)
@Startup
@DependsOn({ D.BEAN_NAME, E.BEAN_NAME })
public class QuestionHandler {
     public static final BEAN_NAME = "C";
     @Inject
     D d;
     @Inject
     E e;
     ...
}

D:

 @Singleton(name = D.BEAN_NAME)
 @Startup
 public class D { 
     public static final BEAN_NAME = "D";
     ...
 }

E:

 @Singleton(name = E.BEAN_NAME)
 @Startup
 public class E { 
     public static final BEAN_NAME = "E";
     ...
 }

【讨论】:

  • 你是对的,问题中有错误。谢谢你指出这一点。我已经修改了问题以更正它们。顺便说一句,QuestionHandler 是 C 类的实际名称。我省略了实际名称,因为它们不会为我的问题增加价值。实际代码在命名上没有这种不一致。因此,您的解决方案没有解决问题,所以我不能接受它作为答案。
  • 我的解决方案仍然有效。您仍然会在@DependsOn 中遇到拼写错误,并且您还假设 Singleton 注册的 bean 名称将与类名称相同,但情况可能并非如此。如果你有一个类 com.packagename.one.A 和一个 com.packagename.two.A 你的一个类将不会有你期望的 bean 名称。
猜你喜欢
  • 2020-08-02
  • 2018-11-28
  • 2013-11-18
  • 2017-10-30
  • 1970-01-01
  • 2020-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多