Jsf 从独立部署的war(未打包在ear中)访问jar中的EJB3Bean

Jsf 从独立部署的war(未打包在ear中)访问jar中的EJB3Bean,jsf,ejb-3.0,Jsf,Ejb 3.0,出于某些原因,我希望将我的应用程序部署为两个独立的构件:Users ejb.jar和Users war.war,而不是打包在同一个ear中(但仍然部署在与7.1实例相同的JBoss中)。在Users war.war中,我有一个支持bean(注释为JSF托管bean),我希望在Users ejb.jar中注入一个打包的EJB3。当用户EJB.jar和用户war.war分别部署时,简单的@EJB注入在所有东西都打包在一个ear中时不再起作用 我的设置的简化示例如下: ejb3bean import

出于某些原因,我希望将我的应用程序部署为两个独立的构件:Users ejb.jarUsers war.war,而不是打包在同一个ear中(但仍然部署在与7.1实例相同的JBoss中)。在Users war.war中,我有一个支持bean(注释为JSF托管bean),我希望在Users ejb.jar中注入一个打包的EJB3。当用户EJB.jar用户war.war分别部署时,简单的@EJB注入在所有东西都打包在一个ear中时不再起作用

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

ejb3bean

import javax.ejb.*;

(...)

@Stateless(name="userFacade")
@Local(IUserFacadeLocal.class)
@Remote(IUserFacadeRemote.class)
public class UserFacade extends AbstractFacade<User> implements IUserFacadeLocal, IUserFacadeRemote {
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;
我尝试过各种组合,比如在支持bean中将EJB3 bean的类型声明为IUserFacadeRemote(与IUserFacadeLocal相反),但是当部署用户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
用户ejb.jar作为7.1部署到JBoss,没有任何抱怨,但是当用户war.war部署时,JBoss抱怨它找不到他应该注入的bean

但是,我能够使用JNDI获得对EJB3Bean的引用,使用:

String jndiName = "java:global/Users-ejb/userFacade!facades.IUserFacadeRemote";
this.userFacade = (IUserFacadeRemote) new InitialContext().lookup(jndiName);
尽管如此,@EJB注入似乎不起作用

更新: 我遵循了下面的建议,有效的注射是:

@EJB(mappedName = "java:global/Users-ejb/userFacade!facades.IUserFacadeRemote")

如果我理解正确,它将使用特定于供应商的mappedName属性。我无法让注入以独立于供应商的方式工作。

我希望我对EE规范的这一领域有足够的了解,能够给您一个明确的答案,但我没有

政府这样说:

  • @EJB注释还有一个mappedName()属性。规范将其保留为特定于供应商的元数据,但JBoss将mappedName()识别为您引用的EJB的全局JNDI名称。如果指定了mappedName(),则会忽略所有其他属性,并将此全局JNDI名称用于绑定
  • 如果指定@EJB时未定义属性[…],则适用以下规则:
    • 在引用bean的ejbjar中搜索带有接口的EJB,用于@EJB注入。如果有多个EJB发布相同的业务接口,则会引发异常。如果只有一个bean具有该接口,则使用该bean
    • 在EAR中搜索发布该接口的EJB。如果存在重复项,则会引发异常。否则将返回匹配的bean
    • 在JBoss中全局搜索该接口的EJB。同样,如果重复,将引发异常
  • @beanName()对应于。如果定义了beanName(),则使用与@EJB相同的算法,不定义任何属性,只将beanName()用作搜索中的键。此规则的一个例外是,如果使用ejb链接“#”语法。“#”语法允许您在引用的EJB所在的EAR中放置jar的相对路径。有关详细信息,请参见规范
“在JBoss中全局搜索该接口的EJB”显然表明,您编写的注入应该可以工作。事实上,它应该在没有
beanName
的情况下工作。然而,我怀疑,从战争中组件的角度来看,EJB-JAR中的组件是远程的,因此需要使用远程接口

因此,我要尝试的第一件事是:

@EJB
private IUserFacadeRemote userFacade;
没有
beanName
,以免造成麻烦。不过,听起来你已经试过了

如果正常的注入方法不起作用,我可能会回头尝试通过
mappedName
进行注入,在JBoss中,mappedName是一个全局JNDI名称。因此:

@EJB(mappedName = "java:global/Users-ejb/userFacade!facades.IUserFacadeRemote")
private IUserFacadeRemote userFacade;
这显然相当丑陋

不管怎样,祝你好运

EDIT:您还可以尝试使用一个限定的相对
beanName
,它显式地命名EJB-JAR:

@EJB(beanName = "Users-ejb.jar#userFacade")
private IUserFacadeRemote userFacade;
因为WAR和EJB-JAR没有打包在EAR中,所以可能需要:

@EJB(beanName = "../Users-ejb.jar#userFacade")
private IUserFacadeRemote userFacade;
但现在我只是在猜测

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


可能有用。这本质上是JBoss特定使用
mappedName

的可移植版本,我一直在Wildfly中测试这个场景,发现如果war中有一个指向ejb的JBoss-deployment-structure.xml,它将与上面描述的本地接口一起工作。否则会抛出ClassNotFoundException,因为上面的war由于JBoss和Wildfly中的模块化类加载而无法真正“了解”EJB类。文件内容应为:

<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="deployment.Users-ejb.jar" />
        </dependencies>
    </deployment>
</jboss-deployment-structure>

正如@TomAnderson所说,实现跨工件查找的标准方法是使用
@EJB
注释

下面是一个完整的Maven项目来说明它是如何工作的:

您不需要使用EJB类的
name
属性,只要在查找中提供类名就足够了。引用上述例子:

// in API JAR
@Remote
public interface HelloService { ... }

// in EJB JAR
@Stateless
public class HelloServiceImpl implements HelloService { ... }

// in WAR
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

    @EJB(lookup = "java:global/service-ear/service-ejb-impl/HelloServiceImpl!" +
                  "ee.mrts.service.HelloService")
    private HelloService helloService;

    ...
}

(因此,直接在
lookup
中使用
HelloServiceImpl
就行了™.)

看看这个。这是给GlassFish的,但可能会有帮助…我的建议有用吗?我很好奇!我现在正在另一个问题上转移注意力,当我尝试你的建议时,我一定会报告。目前我正在使用我在文章末尾添加的JNDI查找工作。@TomAnderson查看我的po上的更新st和我对您的答案的评论。好的,所以“@EJB”不起作用。“@EJB”带有您提供的mappedName属性
@EJB(lookup = "java:global/Users-ejb/userFacade!facades.IUserFacadeRemote")
private IUserFacadeLocal userFacade;
// in API JAR
@Remote
public interface HelloService { ... }

// in EJB JAR
@Stateless
public class HelloServiceImpl implements HelloService { ... }

// in WAR
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

    @EJB(lookup = "java:global/service-ear/service-ejb-impl/HelloServiceImpl!" +
                  "ee.mrts.service.HelloService")
    private HelloService helloService;

    ...
}