WAR 模块中的 EJB 内容
使用本主题来了解 Web 应用程序归档 (WAR) 模块中企业 JavaBeans (EJB) 内容的封装要求。
受支持的 EJB 内容
除了显式声明的限制,封装在 WAR 模块内的 Bean 也支持封装在 EJB Java™ 归档 (JAR) 模块内的 Bean 所支持的 EJB 功能。 封装在 WAR 模块内的 Bean 可以具有与封装在 EJB JAR 模块内的 Bean 相同的行为。
在 WAR 模块以及 2.x 和 1.x 会话 Bean 中支持所有类型的 EJB 3.x bean。请参阅 EJB 3.1 规范以了解完整详细信息。
封装机制
将 EJB 内容封装在 WAR 模块中的规则不同于将 EJB 内容封装在 JAR 模块中的规则。
- 松散地在 WEB-INF/classes 目录结构中
- 在置于 WEB-INF/lib 目录中的 JAR 文件内
例如,您可能松散地将 bean 类 com.foo.MyBean 置于 WAR 模块中的以下位置处:WEB-INF/classes/com/foo/MyBean.class。
您可能还将此 bean 类置于 myJar.jar 文件内,然后将其置于以下位置:WEB-INF/lib/myJar.jar。
WAR 模块可以将某个 bean 代码松散地置于 WEB-INF/classes 目录结构中,且可以将其他 bean 代码置于 WEB-INF/lib 目录中的 JAR 文件内。 对于 WAR 模块,将所有 bean 代码置于 WEB-INF/classes 目录结构中,而完全不置于 WEB-INF/lib 目录中,或者将所有 bean 代码置于 WEB-INF/lib 目录中的 JAR 文件中而完全不置于 WEB-INF/classes 中,这都是有效的。
将多个 JAR 文件(其中都可能包含 Bean 代码)置于 WEB-INF/lib 目录中是有效的。
如果同一 bean 类松散地置于 WEB-INF/classes 目录结构内,还置于 WEB-INF/lib 目录中的 JAR 文件内,那么将装入松散地置于 WEB-INF/classes 目录结构中的类实例,且忽略置于 WEB-INF/lib 目录中的 JAR 文件内的实例。
如果同一 bean 类置于 WEB-INF/lib 目录中的两个不同的 JAR 文件中,那么不知道将装入类的哪个实例,以及将忽略哪个实例。在运行时,服务器任意拾取一个类实例并装入它,然后忽略另一类实例。
- WEB-INF/classes/META-INF/persistence.xml
- WEB-INF/lib/MyEntity.jar
IWAE0068W The EJB deployment descriptor META-INF/ejb-jar.xml in the library archive
foo.jar file is ignored. The product does not process the META-INF/ejb-jar.xml deployment
descriptor in library archives. Move the META-INF/ejb-jar.xml deployment descriptor from the
library archive to the WEB-INF directory in the WAR module.
WAR 模块必须为 v2.5 或更高版本才能包含 EJB 内容。将忽略置于 V2.4 或更高版本的 WAR 模块中的 EJB 内容。

封装在 WAR 文件中的企业 Bean 的技术差异
以下列表包含封装在 WAR 模块中的 Bean 与封装在 EJB JAR 模块中的 Bean 之间存在的关键技术差异:
- 共享组件名称空间
WAR 模块中的所有组件共享单个组件名称空间。这意味着每个 EJB 组件与 WAR 文件中的其他所有 EJB 组件以及任何非 EJB 组件(例如 servlet)共享一个组件名称空间。 相反,封装在 EJB JAR 模块中的 EJB 组件具有自己的专用组件名称空间,不会与其他任何组件共享此空间。
共享的组件名称空间具有重大影响。首先,一个组件(EJB 或非 EJB)可能声明引用,且其他组件可能搜索组件名称空间以查找该引用。其次,一个组件声明的引用可能与另一组件声明的引用冲突。相反,封装在 EJB JAR 模块中的 EJB 无法在组件名称空间中查找其他 EJB 或非 EJB 组件声明的引用,在组件名称空间中,EJB 声明的引用不可能与其他任何组件声明的引用冲突(即使这些引用同名)。
使用共享名称空间时,只要这些引用声明没有相互冲突,就可以多次声明同一引用。如果引用声明没有冲突,那么服务器行为就像只声明一次该引用一样。
如果引用声明有冲突,那么将发出错误消息,而应用程序将无法启动。 为每个有冲突的引用,发出一条警告消息。此警告消息指示冲突的引用的名称以及分配到该引用的多个值。在发出所有警告消息之后,将抛出异常。
- EJB 描述符文件的位置
ejb-jar.xml 部署描述符文件以及其他任何描述符文件都必须置于 WAR 的 WEB-INF 目录中。将忽略 WAR 中其他位置(包括 WEB-INF/lib 目录中 JAR 文件的 META-INF 目录中)的 EJB 描述符文件的任何实例。
- 确定是否扫描注释
对于 EJB JAR 和 WAR 模块,关于确定是否扫描注释的规则不同。请参阅“EJB 3.x 模块封装概述”主题以了解完整的规则集。
- 类加载和可视性
封装在 WAR 模块中的 EJB 类的最常见使用模式是来自同一模块内封装的 Web 组件的本地方法调用。但是,可以通过远程方法调用或通过其他模块中的客户机来访问这些 EJB 类。在这些情况下,重要的是了解封装在 WAR 模块中的 EJB 类的可视性规则。与封装在 JAR 模块中的 EJB 类相比时,可视性规则是不同的。
在远程 EJB 方法调用的情况下,将 EJB 类封装在 WAR 模块中不会引入可视性差异。EJB 绑定到全局名称空间且可以从其他模块中的组件进行查找或注入其中。远程客户机必须使用相应存根类进行方法调用。在本主题中的“存根生成”部分下描述存根类生成。
在从其他模块中的组件进行本地 EJB 方法调用时,存在可视性差异,因为 EJB 封装在 WAR 模块中。因为存在必须考虑的类装入器暗示,所以出现这些可视性差异。
由单个应用程序类装入器实例来装入封装在整个应用程序的所有 EJB JAR 模块中的内容。
相反,在特定于该 WAR 模块的类装入器实例上装入封装在 WAR 模块中的所有内容。用于装入所有 EJB JAR 内容的单个应用程序类装入器实例是用于装入 WAR 内容的每个类装入器实例的父级。
类的可视性受到装入它的类装入器实例影响。类装入器实例可以看到自己装入的类或者由父类装入器装入的类。 但是,类装入器看不到在自身以外的类装入器或其任何父级上装入的类。
因此,由特定于 WAR 模块的类装入器装入的类会看到 EJB JAR 模块中的类,但是它们看不到另一 WAR 模块中的类。 EJB JAR 模块中的类看不到任何 WAR 模块中的类。 例如,如果有封装在 EJB JAR 模块 ejb3.jar 内的 EJB 内容,且还有封装在 ejb1.jar 文件和 ejb2.jar 文件中的 EJB 内容,那么:- 如果 ejb1.jar 文件和 ejb2.jar 文件安装为 EJB JAR 模块,那么在同一类装入器实例上全部装入 ejb1.jar 文件、ejb2.jar 文件和 ejb3.jar 文件内的内容,该实例也用于装入应用程序中的其他任何 EJB JAR 模块。在此情况下,所有三个 JAR 文件中的类都互相可见,因为它们都是由同一类装入器实例装入的。
- 如果 ejb1.jar 文件和 ejb2.jar 文件封装在 WAR 文件的 WEB-INF/lib 目录内,那么 ejb1.jar 文件和 ejb2.jar 文件内的内容由单个类装入器实例装入。但是,此类装入器不是用于装入 ejb3.jar 文件以及应用程序中其他任何 EJB JAR 的内容的同一装入器。在此情况下,ejb1.jar 文件和 ejb2.jar 文件中的类互相可见,且还可以看见 ejb3.jar 文件中的类。 ejb3.jar 文件中的类看不到 ejb1.jar 文件或 ejb2.jar 文件中的类。
- 如果 ejb1.jar 文件封装到 firstWar.war 文件的 WEB-INF/lib 目录中,且 ejb2.jar 文件封装在 secondWar.war 文件的 WEB-INF/lib 目录内,那么在一个类装入器实例内装入 ejb1.jar 文件中的内容,在第二个类装入器实例上装入 ejb2.jar 文件中的内容,在第三个类装入器实例上装入 ejb3.jar 文件以及应用程序中所有其他 EJB JAR 中的内容。在此情况下,ejb1.jar 文件和 ejb2.jar文件中的类互相看不到,但是它们可以看到 ejb3.jar 文件中的类。 ejb3.jar 文件中的类看不到 ejb1.jar 文件或 ejb2.jar 文件中的类。
用于避免这些类装入器混乱的一个策略是将 EJB 接口类封装在共享库内。最佳实践: 请勿将同一类(EJB JAR 模块和 WAR 模块)封装到同一应用程序中。将同一类封装在同一应用程序内的多个位置中可能导致在运行时装入和使用该类的哪个实例方面产生混淆。如果两个 .class 文件表示该类的不同版本,该区分会很重要。为了避免此场景,请将 .class 文件仅封装在一个位置中或者更改类的封装结构,以便封装在 WAR 模块内的类的标准名称不同于封装在 EJB JAR 模块内的类的标准名称。bprac
- 应用程序概要信息扩展
封装在 WAR 模块中的 EJB 类不支持应用程序概要信息扩展。
存根生成
对 EJB 方法的远程访问需要使用客户机端存根类。对于大部分客户机环境,产品运行时自动生成所需的存根类。一个例外是瘦客户机环境。对于瘦客户机,必须手动生成存根类且将其与客户机一起封装。
使用 createEJBStubs 工具在将 EJB 内容封装在 WAR 模块内的时候生成存根(无论 EJB 版本如何)。
请参阅“创建存根”命令主题以了解更多信息。

WAR 模块中的 EJB 2.x 和 1.x 内容
除了实体 bean,在 WAR 模块中支持 EJB 2.x 和 1.x 内容。
封装在 WAR 文件内的 2.x 或 1.x 模块需要 WAR 模块的 WEB-INF 目录中 V2.x 或 V1.x 的 ejb-jar.xml 部署描述符。如果存在 XMI 绑定和扩展文件,您还必须将这些绑定和文件封装在 WAR 模块的 WEB-INF 目录中。
可以将您根据 2.x 或 1.x 编码样式实施的会话 Bean 和消息驱动 Bean 封装在 WAR 模块内。
在 WAR 模块内不支持 Bean 受管持久性 (BMP) 和容器受管持久性 (CMP) 实体 bean。
在 WAR 模块中不支持应用程序概要分析和访问意向服务。在 WAR 模块中找到的会话 Bean 无法访问应用程序概要分析任务。
可以将根据 3.x 编码样式以及 2.x 和 1.x 编码样式实施的 EJB 内容一起封装在单个 WAR 模块中。但是,在此情况下,您必须声明文件的 XML 版本(而不是 XMI 版本)的任何绑定和扩展信息。
将现有 EJB 内容从 EJB JAR 模块移到 WAR 模块
一种方法是将现有 EJB JAR 文件置于 WAR 文件的 WEB-INF/lib 目录中。然后,从 JAR 文件的 META-INF 目录移除描述符文件,然后将其置于 WAR 文件的 WEB-INF 目录中。
第二种方法是将来自 EJB JAR 文件的类文件置于 WAR 模块中的 WEB-INF/classes 目录下的正确位置。然后,从 JAR 文件的 META-INF 目录移除描述符文件,然后将其置于 WAR 文件的 WEB-INF 目录中。
如果将多个 EJB JAR 模块移到单个 WAR 模块中,您必须将先前在 EJB JAR 模块的 META-INF 目录中找到的每个描述符文件的内容合并到描述符文件的单个版本中,现在将这些文件置于 WAR 文件的 WEB-INF 目录中。可能合并的描述符文件的示例包括但不限于 ejb-jar.xml、ibm-ejb-jar-bnd.xml、ibm-ejb-jar-ext.xml 和 ibm-ejb-jar-ext-pme.xml。
您必须检查 WAR 模块中各种组件声明的引用(EJB 和非 EJB)以确保其没有相互冲突,因为 WAR 模块中的一切都共享单个组件名称空间。
您必须修改绑定和扩展 XMI 文件,将其从 EJB JAR 模块移到若干位置的 WAR 模块以移除对 META-INF/ejb-jar.xml 的引用并将其替换为 WEB-INF/ejb-jar.xml。
在 EJB JAR 模块中受支持但是在 WAR 模块中不受支持的 EJB 功能
- BMP 和 CMP 实体 Bean
- EJB 3.1 之前样式启动 Bean注意: 支持由 EJB 3.1 定义的单个启动 Bean。
CWMDF0025E: Entity beans in EJB web application archive (WAR) modules are not allowed,
per the EJB 3.1 specification.
WSVR0039E: Unable to start EJB JAR, foo.war: Entity beans in EJB web application archive
(WAR) modules are not allowed, per the EJB 3.1 specification. The foo bean in the foo.war module
must be moved to a stand-alone EJB module. Examine the log to see a full list of invalid entity
beans in a WAR module.