如何使用CDI将@Iternative与CDI一起注入EJB模块

时间:2013-07-01 10:13:55

标签: java java-ee ejb cdi ear

我想让CDI“选择”替代类作为接口的实现。

虽然EAR中的所有内容都是捆绑包,但是替代实现将在war文件中,其余的(注入接口的类,接口,接口的“默认”实现)将在ejb jar中。

这里有一些代码来说明它:

EJB模块:

public interface I {}

public class C implements I {}

public class A {
  @Inject I var

  public void test() {
    System.out.println(var instanceof C); // I want to have here as Result: false
  }
}

WAR模块:

@Alternative
public class D implements I {}

在war文件中设置beans.xml没有帮助..

2 个答案:

答案 0 :(得分:6)

根据您描述的结构,无法获得所需的注射。

EJB类加载器永远无法访问WAR内的类,因此注入永远不会考虑替代实现。

如果您愿意更改EAR结构,将备选项(D)放在lib / jar中,以及appropriare beans.xml,则可以使用解决方案。 D类将对您的EJB和WAR可见,并且注入应按照需要进行。

修改

我发布的解决方案,我在这里所说的,几乎正在运作。

EAR
  - ejb-module-1.jar 
     - A.class (@Inject I)
     - I.class
     - C.class (@Stateless implements I)
     - META-INF/beans.xml
  - ejb-module-2.jar
     - D.class (@Alternative @Stateless implements I)
     - META-INF/beans.xml (<alternatives><class>D</class></alternative>)
  - app.war
     - calls A.test()
     - WEB-INF/beans.xml

唯一的问题是你错放了beans.xml替代声明。

CDI规范(1.1,但适用于之前的实施)在第5.1章中指出:

  

替代品不适用于注射,查找或EL分辨率   除非模块是bean,否则模块中的类或JSP / JSF页面   存档和替代是在该bean中明确选择的   档案

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

以下是修订后的(和工作)结构:

EAR
  - ejb-module-1.jar 
     - A.class (@Inject I)
     - I.class
     - C.class (@Stateless implements I)
     - META-INF/beans.xml (<alternatives><class>D</class></alternative>)
  - ejb-module-2.jar
     - D.class (@Alternative @Stateless implements I)
     - META-INF/beans.xml (empty <beans></beans>)
  - app.war
     - calls A.test()
     - WEB-INF/beans.xml (empty <beans></beans>)

还要记住,虽然对于标准bean,替代选择仅对于模块中的工作,但在beans.xml 中声明了替代方案,但对于EJB来说却不是这样。因此,您的D替代方案(@Stateless)对整个应用程序都有效。

答案 1 :(得分:2)

自CDI 1.1以来。您可以使用@Priority,以便在全局范围内发现您的替代方案 - 请参阅此处Dependency injection and programmatic lookup

如果您使用@Priority,则无需在beans.xml中声明替代方法 - 请参阅此处Using Alternatives in CDI Applications