EJB 3.x 模块打包概述
本主题描述了当您使用 Enterprise JavaBeans (EJB) 3.x Bean 时的应用程序封装。
封装使用 EJB 3.x Bean 的应用程序与 Java™ Platform, Enterprise Edition (Java EE) 1.4 应用程序的组装需求相似:将组件封装到模块中,模块又封装到应用程序企业归档 (EAR) 文件中。组件和模块都在可扩展标记语言 (XML) 部署描述符中提供描述元数据。EJB 3.x 规范支持使用其他方法来描述元数据和封装持久性单元。
- 包含 EJB 模块的 Java 应用程序归档 (JAR) 文件。Java EE 应用程序客户机模块和实用程序类模块。
- 包含 Web 模块或 EJB 内容的 Web 应用程序归档 (WAR) 文件。WAR 文件的版本必须为 V2.5 或更高版本,才能包含 EJB 内容。
- 其他特定于技术的模块(例如资源应用程序归档 (RAR) 文件)以及其他类型的模块。
不包含部署描述符的 EJB 模块
如果您使用的是 EJB 3.x Bean,那么可以封装不包含部署描述符的 EJB 模块。为此,您必须使用位于 EJB 组件中的注释包含的元数据来创建 JAR 文件或 WAR 文件。在 ejb-jar.xml 文件中,EJB 3.x Bean 不需要具有已通过注释定义的元数据的条目。
对于 EJB 3.0,缺省情况是在安装 EJB 3.0 模块期间扫描注释。对于 WebSphere® Application Server V9.0,缺省情况是在安装应用程序或者服务器启动期间不扫描版本低于 Java EE 5 的模块。
为了与 Feature Pack for EJB 3.0 和 Feature Pack for Web Service 都保持向后兼容,您可以选择是否扫描旧的 Web 模块以获取更多元数据。为每个功能部件包扫描行为定义了服务器级别的交换机。如果缺省值不合适,那么必须在需要更改缺省值的每个服务器和管理服务器上设置交换机。交换机是服务器定制属性 com.ibm.websphere.webservices.UseWSFEP61ScanPolicy={true|false} 和 com.ibm.websphere.ejb.UseEJB61FEPScanPolicy={true|false}。要在管理控制台中定义这些属性,请单击
。包含部署描述符的 EJB 模块
您可以继续使用具有部署描述符的 EJB 模块。包含部署描述符的模块可支持任何 EJB 规范版本级别(包括 EJB 3.x),但是这些描述符通常应反映模块中组件的实现要求。
EJB 模块可以具有 EJB 3.x、2.x 或 1.x 部署描述符。
对于 EJB 2.x 或者 EJB 1.x 部署描述符,假定部署描述符包含模块的完整元数据,并且不对注释元数据进行任何其他扫描。
对于不具备部署描述符的 EJB 模块或者对具有 EJB 3.0 模式级别的 ejb-jar.xml 部署描述符的 EJB 模块执行 EJB 容器注释扫描,并且 metadata-complete XML 属性设置为 false;或者省略对此 EJB 模块执行 EJB 容器注释扫描。有关服务器用来确定是否执行了注释扫描的完整规则集,请参阅“注释扫描行为”一节。
注释扫描行为
服务器可以检查模块中的类文件以查找注释内容。服务器将搜索可以定义组件、对资源的引用或者特殊行为的注释内容。例如,可以使用注释来定义 EJB 组件、声明对于 EJB 组件必须使用的数据源的引用或者声明与 EJB 方法相关联的事务属性或安全性属性。此检查过程称为注释扫描。如果模块中的类文件包含必须由服务器进行检查的注释,那么必须配置服务器以便进行注释扫描。如果模块中的类文件不包含注释,那么由于性能方面的原因,您可以配置服务器以便不进行注释扫描。
- 是否存在 ejb-jar.xml 部署描述符文件
- ejb-jar.xml 部署描述符(如果存在)的版本
- ejb-jar.xml 部署描述符(如果存在)中的 metadata-complete 设置的值
- web.xml 部署描述符的版本(当 EJB 内容封装在 WAR 模块中,并且不存在 ejb-jar.xml 部署描述符时)
- web.xml 部署描述符中的 metadata-complete 设置的值(当 EJB 内容封装在 WAR 模块中,并且不存在 ejb-jar.xml 部署描述符时)
下列各表指出如何决定对封装在 EJB JAR 模块或者 WAR 模块中的 EJB 内容进行注释扫描或者不扫描。
ejb-jar.xml | ejb-jar.xml 中的 metadata-complete 值 | 是否扫描了注释? |
---|---|---|
存在,版本为 V2.x 或更低版本 | 不适用 | 否 |
存在,版本为 V3.x 或更高版本 | true | 否 |
存在,版本为 V3.x 或更高版本 | false(或者已省略) | 是 |
不存在 | 不适用 | 是 |
ejb-jar.xml 文件 | ejb-jar.xml 中的 metadata-complete 值 | web.xml 文件 | web.xml 中的 metadata-complete 值 | 是否扫描了注释? |
---|---|---|---|---|
存在,版本为 V3.x 或更高版本 | true | 不适用 | 不适用 | 否 |
存在,版本为 V3.x 或更高版本 | false(或者已省略) | 不适用 | 不适用 | 是 |
存在,版本为 V2.x 或更低版本 | 不适用 | 不适用 | 不适用 | 否 |
不存在 | 不适用 | 存在,版本为 V2.5 或更高版本 | true | 否 |
不存在 | 不适用 | 存在,版本为 V2.5 或更高版本 | false(或者已省略) | 是 |
不存在 | 不适用 | 存在,版本为 V2.4 或更低版本 | 不适用 | 否 |
不存在 | 不适用 | 不存在 | 不适用 | 是 |
了解 ejb-jar.xml 部署描述符的 ejb-jar 元素的 metadata-complete 属性与可以在安装应用程序或模块的过程中指定的 metadata-complete 安装设置之间的区别至关重要。
ejb-jar.xml 文件的 ejb-jar 元素的 metadata-complete 属性是一个 XML 属性。服务器使用此属性来确定是否必须扫描类以获取注释数据,正如“EJB 内容的注释扫描”表中的规则所描述的那样。
相比之下,服务器使用可能是在安装时指定的 metadata-complete 设置来帮助生成 ejb-jar.xml 文件。如果模块中不存在 ejb-jar.xml 文件,并且为 metadata-complete 安装设置所指定的值为 true,那么服务器将扫描注释内容并使用该内容来生成 ejb-jar.xml 文件,然后在该文件中将 XML 属性 metadata-complete 设置为值 true。
持久性单元
持久性单元(包含 persistence.xml 文件及其关联类)可封装在需要这些单元的模块中。它们也可以封装在单独的实用程序 JAR 文件中,而该文件与其从属模块一起封装在 EAR 文件中。
应用程序封装
可在同一应用程序中同时使用 EJB 2.x 和更低版本的 Bean 以及 EJB 3.x Bean。但是,在 EJB 2.x 或 EJB 1.x 模块中不识别 EJB 3.x Bean。
- 应用程序名称假定为 EAR 文件的名称,但不包含 EAR 文件扩展名。
- 以 .war 结尾的文件假定为 Web 模块。Web 模块的上下文根是相对于应用程序包的根的文件名,但是已移除 WAR 文件扩展名。
- 以 .jar 结尾且不存在于 /lib 目录中的文件,包含 ejb-jar.xml 文件或者至少包含一个用于定义 @Stateful、@Stateless、@Singleton 或 @MessageDriven 注释的类的文件均假定为 EJB 模块。
- 其他不在 /lib 目录中的 JAR 文件均不假定为 EJB 模块。
JPA 封装
建议将持久性单元封装在单独的 JAR 文件中,以使它们更易于访问和复用。不论是否进行了实际的数据库持久化,都可以在容器外部测试这些持久性单元。持久性单元可包括在独立应用程序中,或者作为实用程序 JAR 文件包括在 EAR 文件中。由于扫描大量类时存在各种用例和潜在性能问题,因此建议在持久性单元中定义持久性单元的类。
用于持久性方案的会话面
公共模式会将会话面用于持久化。支持使用会话 Bean 外观来驱动 JPA。EntityManager 接口不是线程安全的,因此 Servlet 应该从不注入 @PersistenceContext。Servlet 必须使用外观模式或使用 EntityManagerFactory 实例对每个请求创建一个 EntityManager。
建议在单独的 JAR 文件中,除了定义会话 Bean 外观之外,还应该定义 JPA 持久性单元。这不但是极大提高共享灵活性的最佳实践,而且可避免将 JPA 和非 JPA 注释类混合使用所导致的问题。
通常,将创建 JAR 文件以容纳实体类和 JPA persistence.xml 定义并将该 JAR 文件作为实用程序 JAR 文件添加到 EAR 文件。EJB 3.x 模块通过在 EJB 3.x 模块 MANIFEST.MF 中声明某一依赖项来对 JAR 文件添加该依赖项。例如,如果 EAR 包含 TradeApp.ear、TradeWeb.war、EJB3Trade.jar 和 TradeInfo.jar 文件,那么 EJB3Trade.jar 文件将具有类似以下的 MANIFEST.MF:
Manifest-Version: 1.0
Class-Path: TradeInfo.jar
EJB3Trade.jar 文件中的会话面指的是 TradeInfo.jar 文件中的 JPA 实体类和持久性单元。TradeWeb.war 文件中定义的 Web 应用程序可执行相同操作,以便将 JPA 实体对象作为 Web 和 EJB 容器层之间流动的数据传输对象进行处理。
跨层和跨版本会话 Bean 引用方案
可以使用多种方法来定义和使用对于 EJB 3.x 会话 Bean 的引用。对于 EJB 3.x 会话到会话,可以使用 @EJB 注入目标。对于跨层会话(例如,Web 应用程序到 EJB 3.x 会话)或跨版本会话(例如,EJB 2.1 会话到 EJB 3.x 会话),可使用 XML 部署描述符引用来定义 ejb-ref 和 ejb-local-ref。它们存在两种变体,取决于是引用了 EJB 3.x 业务接口,还是引用了也定义了 EJBLocalHome 的版本低于 EJB 3.x 的组件类型接口。如果可使用自动链接来解析所引用的组件,那么 Web 应用程序和客户机应用程序也可以使用 @EJB 注释。
先前方案将 EJB 2.1 类型的客户机模式与 EJB 3.x 类型的会话 Bean 实现配合使用。对于最近的客户机类型,可以清理客户端以直接查询会话 Bean 业务接口,而不用通过 Home 接口来查询。在这种情况下,不需要定义 @LocalHome(<localhome>.class) 注释。可使用 ejb-ref 和 ejb-local-ref 的变体定义来实现此目的。使用 null 值作为 local-home 元素值并将 ejb-local-ref 绑定至会话 Bean 的 ejblocal: 绑定而不是 home 绑定。例如:
<ejb-local-ref id="EJBLocalRef_1154112538064">
<description>com.ibm.persistence.ejb3.order.facadecom.ibm.persistence.ejb3.order.facade</description>
<ejb-ref-name>ejb/OrderEJB</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local-home></local-home>
<local>com.ibm.persistence.ejb3.order.facade.OrderProcessor</local>
</ejb-local-ref>
还必须对客户机代码进行调整,以便对要查询的对象执行适当的强制类型转换。在这种情况下,使用业务接口取代 Home 接口:
try {
InitialContext ctx = new InitialContext();
orderProcessor = (OrderProcessor)ctx.lookup("java:comp/env/ejb/OrderEJB");
}
catch(Exception e) {
e.printStackTrace(System.out);
throw new ServletException(e);
}