【问题标题】:How to properly use @Alternative for client implementations如何正确使用@Alternative 进行客户端实现
【发布时间】:2012-09-25 18:14:28
【问题描述】:

编辑:我将 CDI 注入点从使用 @EJB 更改为使用 @Inject,如下面的 cmets 所示。仅供参考。


我有两个 EAR 项目,两者基本相同。他们唯一的区别是一些客户特定的实现,如果需要的话。但是,我遇到了问题。

这就是我所拥有的:

EAR #1 包含以下模块:

web.war 
ejb-default.jar
ejb-client-1.jar

EAR #2 包含以下模块:

web.war
ejb-default.jar
ejb-client-2.jar

在ejb-default中包含以下内容:

@Singleton
@Startup
public class ApplicationSettingsBean implements ApplicationSettingsBeanLocal

现在,对于 EAR #1,ejb-client-1.jar 可能为空,因此任何 EJB 注入都应使用 ejb-default 中的任何内容。

但是,对于 EAR #2,我想用特定于客户端的实现来覆盖默认实现。例如:

@Singleton
@Startup    
@Alternative
public class ApplicationSettingsBean implements ApplicationSettingsBeanLocal {

我还在 ejb-client-2 中创建了以下 beans.xml 条目:

<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    <alternatives>
        <class>com.client2.ejb.ApplicationSettingsBean</class>
    </alternatives>
</beans>

我希望@Alternative 实现会在这样的实现存在时被注入。如果在注入点指定了@Default,则应该注入默认实现(ejb-default)。不过,这不会发生:

    // Inject the alternative implementation
    @Inject
    private ApplicationSettingsBeanLocal appSettingsBean;

使用此 CDI,注入的是默认值,而不是替代方法。这不是预期的行为。

【问题讨论】:

  • 因此,按照 Gavin King 在另一个论坛上的建议,我将所有注入点从使用 @EJB 更改为 @Inject,从而消除了错误。但是,它并没有解决问题。现在,@Alternative 实现被忽略,取而代之的是@Default(隐含注释)实现。我在第二个 EJB jar 中仔细检查了 beans.xml,它看起来不错。
  • 以上代码已更改以反映问题。

标签: jakarta-ee ejb cdi ejb-3.1 qualifiers


【解决方案1】:

beans.xml,您必须在其中指定替代项, 必须在 ejb-default.jar 内,而不是在 ejb-client-2.jar 内。

CDI 规范(1.1,但也适用于之前的实现)在第 5.1 章中声明:​​

替代方法不适用于注入、查找或 EL 解析 到模块中的类或 JSP/JSF 页面,除非模块是 bean 存档,并且在该 bean 中明确选择了替代方案 存档。

换句话说,您必须在使用该 bean 的类的同一模块中选择替代项。

【讨论】:

  • 遇到了同样的问题,一个 WAR 模块引用了一个包含一些无状态 bean 的简单 JAR。其中之一的接口通过 CDI 注入到 WAR 中的 REST 资源中。尽管 JAR 中的 IT 测试很好并且花了我 3 小时的研究,直到我找到了你的帖子,但没有工作。谢谢伙计,现在我可以去圣诞节了;)
【解决方案2】:

对于那些想知道发生了什么的人,这混合了 CDI 和 EJB (EE5) 注入。这就是发生第一个错误的原因。替代方案是 CDI 想法,@EJB 无法识别它们。

默认而不是替代的原因是因为这是在注入中使用的限定符(替代没有隐含@Default)。这实际上告诉 CDI 我确切地知道我想要哪个实例,它是我在注入时使用的具有相同限定符的实例。处理此类事情的最佳方法是简单地使用 @Inject 而不使用任何限定符,除非您确切知道您想要哪个实例并将这些限定符添加到注入中(与实现类中的相同)。

【讨论】:

  • 是的,就这样。我花了一分钟才发现@Alternative 仅适用于@Inject 注入点,不适用于@EJB。然而,在进行需求更改后,@Alternative 类仍然无法通过默认实现识别。知道为什么会这样吗?
  • 您使用的是哪个应用服务器?还有你的 beans.xml 文件在哪里,尤其是有替代方案的文件?战争在哪里被调用?
  • 我使用的是 Glassfish 3.1.2。我在ejb-default.jar 中有一个空的beans.xml,其中包含默认实现。我在ejb-client-2.jar 中有一个beans.xml(带有适当的备用标记),其中包含@Alternative 实现。我正在从 WAR 中的托管 bean 注入 EJB(使用 @Inject)。
  • 我认为这是问题所在,来自战争。战争对替代方案一无所知。只是为了踢球和咯咯笑,将替代方案添加到战争中,看看会发生什么。如果您不在 3.1.2.2 上,您也可以尝试一下,看看是否有帮助。
  • 我会尝试并报告。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-07
  • 1970-01-01
  • 2010-09-25
  • 1970-01-01
  • 2012-05-21
  • 2017-09-15
  • 1970-01-01
相关资源
最近更新 更多