Jsf 从独立部署的war(未打包在ear中)访问jar中的EJB3Bean
出于某些原因,我希望将我的应用程序部署为两个独立的构件: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中时不再起作用 我的设置的简化示例如下: ejb3beanJsf 从独立部署的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
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的相对路径。有关详细信息,请参见规范
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;
...
}