从独立部署的战争中访问jar中的EJB3 bean(未包装在耳中)

Mar*_*tus 7 jsf ejb-3.0

出于某些原因,我想将我的应用程序部署为两个单独的工件:Users-ejb.jarUsers-war.war,未打包在同一个耳中(但仍然部署在同一个 JBoss AS 7.1实例中).在Users-war.war中,我有一个支持bean(注释为JSF托管bean),我希望在其中注入打包在Users-ejb.jar中的EJB3 .当Users-ejb.jarUsers-war.war单独部署时,当所有内容都打包在单个耳朵中时,简单的@EJB注入不再有效.

我的设置的简化示例如下:

EJB3 bean

import javax.ejb.*;

(...)

@Stateless(name="userFacade")
@Local(IUserFacadeLocal.class)
@Remote(IUserFacadeRemote.class)
public class UserFacade extends AbstractFacade<User> implements IUserFacadeLocal, IUserFacadeRemote {
Run Code Online (Sandbox Code Playgroud)

支持豆

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.ejb.EJB;

import entities.User;
import facades.IUserFacadeRemote;
import facades.IUserFacadeLocal;

@ManagedBean(name="indexBackingBean")
@SessionScoped
public class IndexBackingBean implements Serializable {

    @EJB(beanName="userFacade")
    private IUserFacadeLocal userFacade;
Run Code Online (Sandbox Code Playgroud)

我尝试了各种组合,比如在支持bean中声明EJB3 bean的类型为IUserFacadeRemote(而不是IUserFacadeLocal),但是当部署Users-war.war模块时,它们都会失败并出现相同的异常:

Caused by: org.jboss.as.server.deployment.DeploymentUnitProcessingException:
JBAS014543: No EJB found with interface of type 'facades.IUserFacadeLocal' and
 name 'userFacade' for binding controllers.IndexBackingBean/userFacade
Run Code Online (Sandbox Code Playgroud)

用户-ejb.jar被部署到JBoss AS 7.1没有任何抱怨,但是当用户-war.war部署时,JBoss抱怨说,它无法找到他应该注入豆.

但是,我可以使用JNDI获取对EJB3 bean的引用:

String jndiName = "java:global/Users-ejb/userFacade!facades.IUserFacadeRemote";
this.userFacade = (IUserFacadeRemote) new InitialContext().lookup(jndiName);
Run Code Online (Sandbox Code Playgroud)

尽管如此,@ EJB注射似乎不起作用.

更新: 我遵循汤姆安德森下面给出的建议,并且有效的注射是:

@EJB(mappedName = "java:global/Users-ejb/userFacade!facades.IUserFacadeRemote")
Run Code Online (Sandbox Code Playgroud)

如果我理解正确使用特定于供应商的mappedName属性.我不能让注入以独立于供应商的方式工作.

Tom*_*son 4

我希望我能够很好地理解 EE 规范的这一领域,以便为您提供明确的答案,但我没有。

JBoss EJB 文档是这样说的:

  • @EJB 注释还有一个mappedName() 属性。该规范将其保留为供应商特定的元数据,但 JBoss 将mappedName() 识别为您正在引用的EJB 的全局JNDI 名称。如果您指定了mappedName(),则所有其他属性都将被忽略,并使用此全局JNDI 名称进行绑定。
  • 如果您指定 @EJB 且未定义任何属性 [...],则适用以下规则:
    • 搜索引用 bean 的 EJB jar 来查找带有接口的 EJB,用于 @EJB 注入。如果有多个 EJB 发布相同的业务接口,则会引发异常。如果只有一个 bean 具有该接口,则使用该 bean。
    • 在 EAR 中搜索发布该接口的 EJB。如果存在重复项,则会引发异常。否则返回匹配的 bean。
    • 在 JBoss 中全局搜索该接口的 EJB。同样,如果重复,则会引发异常。
  • @EJB.beanName() 对应于 . 如果定义了 beanName(),则使用与 @EJB 相同的算法,但不定义任何属性,只是使用 beanName() 作为搜索中的键。此规则的一个例外是如果您使用 ejb-link '#' 语法。“#”语法允许您在 EAR 中放置您所引用的 EJB 所在的 jar 的相对路径。请参阅规格了解更多详细信息

“在 JBoss 中全局搜索该接口的 EJB”无疑表明像您编写的那样的注入应该可以工作。事实上,它应该在没有beanName. 然而,我怀疑从 WAR 中的组件的角度来看,EJB-JAR 中的组件是远程的,因此您需要使用远程接口。

所以,我要尝试的第一件事是:

@EJB
private IUserFacadeRemote userFacade;
Run Code Online (Sandbox Code Playgroud)

没有beanName,以防造成麻烦。不过,听起来你已经尝试过了。

如果正常的注入方法不起作用,我可能会转而尝试通过 a 进行注入mappedName,这在 JBoss 中是全局 JNDI 名称。所以:

@EJB(mappedName = "java:global/Users-ejb/userFacade!facades.IUserFacadeRemote")
private IUserFacadeRemote userFacade;
Run Code Online (Sandbox Code Playgroud)

这显然是相当丑陋的。

无论如何,祝你好运!

编辑:您可以尝试的其他方法是使用beanName显式命名 EJB-JAR 的限定亲属:

@EJB(beanName = "Users-ejb.jar#userFacade")
private IUserFacadeRemote userFacade;
Run Code Online (Sandbox Code Playgroud)

由于 WAR 和 EJB-JAR 未打包在 EAR 中,因此可能需要:

@EJB(beanName = "../Users-ejb.jar#userFacade")
private IUserFacadeRemote userFacade;
Run Code Online (Sandbox Code Playgroud)

但到目前为止我只是猜测。

编辑反击:我们可能忽略了一些非常简单的事情。lookup注释的属性允许@EJB您指定“包含目标 EJB 组件的 JNDI 名称的可移植查找字符串”,因此:

@EJB(lookup = "java:global/Users-ejb/userFacade!facades.IUserFacadeRemote")
private IUserFacadeRemote userFacade;
Run Code Online (Sandbox Code Playgroud)

可能有用。这本质上是 JBoss 特定使用的可移植版本mappedName