Glassfish+NetBeans:为什么 JSF Web App 作为展示模块需要同时引用 EJB API 模块和 EJB 实现模块

Glassfish+NetBeans: Why does JSF Web App as presentation module need to reference both EJB API module and EJB implementation module

Glassfish4.1.1(或 Payara41) Java EE 7

[编辑:简单的 answer/solution 可能是 "don't do it that way, use an EAR instead",但它有一些缺点,见底部]


我正在探索模块化大型网络应用程序的策略。我在文件夹 /multi-ant 下有以下结构(注意所有项目模块都是 NetBeans Ant 样式的项目版本):

multi-ant/
├── CoreAPIAnt       (NetBeans Java Class Library project)
├── CoreEJBAnt       (NetBeans EJB Module project)
├── CoreWebAnt       (NetBeans Web Application Project, WAR + extra JAR build)

系统(如此处所示)仅使用@Local 接口(还有一个@Remote 方面和未显示的独立应用程序客户端)。

CoreWebAnt 可以 运行 独立作为具有 WAR 结构的 JSF Web 应用程序。

在 CoreEJBAnt 中,我有一个元素实体并且:

@Stateless
public class ElementQuery implements IElementQuery {

其中 IElementQuery 在 CoreAPIAnt 中,它是一个 NetBeans Java Class 库项目:

@Local
public interface IElementQuery extends Serializable {

在我的 CoreWebAnt JSF 网络应用程序中:

...
import javax.inject.Named;
import javax.faces.view.ViewScoped;

@Named(value = "elementManager")
@ViewScoped
public class ElementManager implements Serializable {

    @EJB private IElementQuery elementQuery;

目标是让 Web 应用程序模块与 EJB 实现无关,但是如果我只是将 CoreAPIAnt 设置为 CoreWebAnt 中的项目依赖项 (dist/CoreAPIAnt.jar)(不参考dist/CoreEJBAnt.jar) 然后部署 CoreEJBAnt 和 CoreWebAnt,CoreWebAnt 中使用的 ElementManager 无法解析针对 IElementQuery 的注入,我收到此错误:

Severe:   Cannot resolve reference Local ejb-ref name=com.example.multi.core.web.ElementManager/elementQuery,Local 3.x interface =com.example.multi.core.api.IElementQuery,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session
Severe:   Exception while deploying the app [CoreWebAnt]
Severe:   Exception during lifecycle processing
java.lang.RuntimeException: Cannot resolve reference Local ejb-ref name=com.example.multi.core.web.ElementManager/elementQuery,Local 3.x interface =com.example.multi.core.api.IElementQuery,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session
    at com.sun.enterprise.deployment.util.ComponentValidator.accept(ComponentValidator.java:374)

如果我 将 CoreEJBAnt 作为项目依赖项包含在 CoreWebAnt 中(因此 dist/CoreEJBAnt.jar 在其 /lib 下可用)我可以 运行 CoreWebAnt 完全独立(无需首先部署 CoreEJBAnt)。 但这违背了拥有仅接口核心APIAnt 模块的全部目的。

问:为什么 Glassfish 不能 "see" 并解析已部署的 CoreEJBAnt 中的注入实现候选 @Stateless ElementQuery(对比 CoreAPIAnt 中使用的 @EJB IElementQuery CoreWebAnt) 当 CoreWebAnt 单独 运行 并且只依赖于 CoreAPIAnt.jar ?

我希望尽可能避免 @Remote 的开销(以及实体通过 RMI 返回的所有后果)并暂时完全留在 @Local 开发生态系统中。

必须从 Web 应用程序引用 CoreEJBAnt 模块并不是世界末日,但它打破了 vs-API 规则,我想了解为什么这里也需要它.


编辑:EAR 方法(经过更多调查)

如果我在 NetBeans 中创建一个空的 EAR 项目(没有嵌套的 EJB 模块或 Web App 模块),我可以在Java EE Modules 节点添加 CoreEJBAnt.jar 和 CoreWebAnt.war,如果 CoreWebAnt 模块没有项目依赖性,它 运行 没问题实现模块CoreEJBAnt(它只需要CoreAPIAnt)。分解后的分布结构如下:

$ tree -L 3 CoreEAR/dist/gfdeploy/
CoreEAR/dist/gfdeploy/
└── CoreEAR
    ├── CoreEJBAnt_jar
    │   ├── CoreAPIAnt.jar
    │   ├── META-INF
    │   ├── com ...
    │   └── rebel.xml
    ├── CoreWebAnt_war
    │   ├── META-INF
    │   ├── WEB-INF
    │   ├── index.xhtml
    │   └── resources
    ├── META-INF
    │   └── MANIFEST.MF
    ├── gfv3ee6.dpf
    ├── lib
    │   ├── CoreAPIAnt.jar
    │   └── other.jar

它甚至可以很好地在 lib 下引入其他 JAR 库我还不得不放入 CoreWebAnt 的 lib 以使其 运行 独立。

然而,我在使用 JRebel 时遇到了一些新的错误,尽管它确实在 CoreWebAnt 和 CoreEJBAnt 项目中捕获并热重新加载编辑中的更改。

所以我的问题的答案可能确实是 "don't try to use the standalone web app, use the EAR approach",但我仍然想知道为什么 Glassfish 没有设计为让 Web 应用 "see" 单独部署EJB 模块。我没有在规格中找到任何关于它的具体信息。

Java™ 平台企业版 (Java EE) 规范 v7 提供了对运行时要求的清晰描述 class 在 应用程序组装和部署 部分的可见性。

这是所有完整的 Java EE 服务器(例如 GlassFish 和 WildFly)实现的。

单独部署的组件(部署单元)的隔离是有意的。