Java 在多项目环境中避免不明确依赖关系的著名策略

Java 在多项目环境中避免不明确依赖关系的著名策略,java,jakarta-ee,cdi,glassfish-4,java-ee-7,Java,Jakarta Ee,Cdi,Glassfish 4,Java Ee 7,我有一个多Maven项目的设置,最终打包为EAR归档。 这些项目属于jar、ejb或war类型 现在我有了一个javax.enterprise.context.SessionScopedCDIBean, 注释为javax.enterprise.inject.Default, 携带关于当前用户的信息(主要从Shiro框架中检索)。 我还有两个自治的Web应用程序,它们应该使用这个Bean,所以我把这个Bean放在一个项目中,由两个项目引用 我现在的问题是,我在部署过程中遇到了一个异常,告诉我Bea

我有一个多Maven项目的设置,最终打包为EAR归档。 这些项目属于jar、ejb或war类型

现在我有了一个
javax.enterprise.context.SessionScoped
CDIBean, 注释为
javax.enterprise.inject.Default
, 携带关于当前用户的信息(主要从Shiro框架中检索)。 我还有两个自治的Web应用程序,它们应该使用这个Bean,所以我把这个Bean放在一个项目中,由两个项目引用

我现在的问题是,我在部署过程中遇到了一个异常,告诉我Bean不能被注入,因为有两个可能的依赖项,它们指向完全相同的类。 我猜这是因为包含Bean的项目(Jar项目)连接到两个Web项目,并且Bean被多次发现

所以我的问题是: 是否有一种众所周知的策略来处理此类问题,或者有某种方法来向应用服务器/CDI实现发出信号(我的示例中的Glassfish 4.x使用Weld Framework),以便只阅读一次

我确实注意到有可能使用
javax.enterprise.inject.Instance
,但我不想使用它,因为允许更改当前操作用户的快照对应用程序至关重要。 我还考虑了通过API和实现项目提供这些Bean的方法,仅将API作为依赖项引用,但这将产生巨大的开销,因为这些项目目前每个只包含一个类

这是我的Beans类标题:

package omega1001.mediaserver.domainmodel.web;

import ...;


@SessionScoped
@Default
public class OmegaMediaServerSubject implements Serializable {
这就是我尝试注入Bean的方式:

@Inject
    private OmegaMediaServerSubject subject;
这是我在部署时遇到的例外情况:

org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type OmegaMediaServerSubject with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private omega1001.mediaserver.servlet.messageProcessor.DefaultMessageProcessor.subject
  at omega1001.mediaserver.servlet.messageProcessor.DefaultMessageProcessor.subject(DefaultMessageProcessor.java:0)
  Possible dependencies: 
  - Managed Bean [class omega1001.mediaserver.domainmodel.web.OmegaMediaServerSubject] with qualifiers [@Default @Any],
  - Managed Bean [class omega1001.mediaserver.domainmodel.web.OmegaMediaServerSubject] with qualifiers [@Default @Any]
    at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:367)
    at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:281)
    at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:134)
    at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:155)
    at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:518)
    at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:504)
    at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:479)
    at org.jboss.weld.bootstrap.WeldStartup.validateBeans(WeldStartup.java:443)
    at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:90)
    at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:225)
    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:496)
    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 org.glassfish.admin.rest.utils.ResourceUtil.runCommand(ResourceUtil.java:253)
    at org.glassfish.admin.rest.utils.ResourceUtil.runCommand(ResourceUtil.java:231)
    at org.glassfish.admin.rest.utils.ResourceUtil.runCommand(ResourceUtil.java:275)
    at org.glassfish.admin.rest.resources.TemplateListOfResource.createResource(TemplateListOfResource.java:133)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
    at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:309)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:292)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1139)
    at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer.service(GrizzlyHttpContainer.java:375)
    at org.glassfish.admin.rest.adapter.RestAdapter$2.service(RestAdapter.java:316)
    at org.glassfish.admin.rest.adapter.RestAdapter.service(RestAdapter.java:179)
    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:206)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
    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:283)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:132)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:111)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:536)
    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:591)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
    at java.lang.Thread.run(Thread.java:745)

我现在明白了

正如Steve C所指出的:

包含讨论中的Bean的项目与这两个Web项目一起打包

简单的解决方案是将依赖项Maven范围更改为Web项目中提供的依赖项,然后将其作为EAR中的库提供

因此,回答我的问题:

是的,有一个众所周知的策略来处理这类问题,即确保提供包含您的共享bean的项目,但不要将该项目与目标EAR之外的任何其他项目打包

感谢Steve C为您指路

致以最良好的祝愿


J.Adam

在我看来,在不同的项目中共享CDI bean不是一个好主意。我更愿意将用户信息重构到一个单独的项目中,例如UserService,它提供了一个清晰的接口(例如JAX-RS),可以被两个web应用程序使用。如果web应用程序是自包含的,不依赖于共享库,那么您将面临较少的问题。这闻起来很像您将包含
OmegaMediaServerSubject
bean的jar内置到EAR中,以及一个或两个WAR文件的web-INF/lib目录中。您需要确保已将maven ear插件配置为生成。@simdevmon您的想法与我的API/Impl方法类似。但正如我所指出的,这将是“巨大的开销,因为这些项目目前每个只包含一个类”。此外,这只是提供用户信息的一个机会。所以我认为这通常是一种有效的方法,但并不完全是我想要的。非常感谢。anyway@SteveC没错,Maven将公共项目与两个Web项目打包在一起。我将验证这是我问题的答案,然后制定一个答案。谢谢你带路。