Show Table of Contents
3.2.11. EJB 2.x 的修改
3.2.11.1. 更新使用 EJB 2.x 的应用程序
JBoss EAP 6 构建于开放式标准,它和 Java EE 6 规格兼容。虽然应用程序服务器支持 EJB 2.x,但它不会再支持超过这个规格的功能。请记住,Java EE 7 规格已经将 EJB 2.x 标记为可选的,所以我们强烈推荐您根据 EJB 3.x 规格重写您的应用程序。
如果您仍想移植 EJB 2.x 代码,多数情况下您需要修改代码以在 JBoss EAP 6 里运行。本节描述了其中一些修改。
在 JBoss EAP 6 上运行 EJB 2.x 所需的配置修改
- 用 Full 配置集启动服务器
- EJB 2.x Container Managed Persistence (CMP) bean 要求 Java EE 6 Full 配置集。这个配置集包含运行 CMP EJB 所需的配置元素。这个配置集包含了
org.jboss.as.cmp扩展模块:<extensions> ... <extension module="org.jboss.as.cmp"/> ... </extensions>它也包含cmp子系统:<profiles> ... <subsystem xmlns="urn:jboss:domain:cmp:1.1"/> ... </profiles>.要用 Full 配置集启动 JBoss EAP 6 独立服务器,在用命令行启动服务器时请使用-c standalone-full.xmlor-c standalone-full-ha.xml参数。 - 容器配置不再被支持了
- 在以前的 JBoss EAP 版本里,我们可以为 CMP 实体和其他 bean 配置不同的容器并通过在
jboss.xml部署描述符文件里设置引用来使用它。例如,对于 SLSB 对 Session Bean 的引用通常有不同的配置。在 JBoss EAP 6.x 里,我们可以将 EJB 2 Entity Bean 和标准容器一起使用。然而,它不再支持不同的容器配置。推荐的做法是移植 EJB2 Stateful Session Bean(SFSB)、Stateless Session Beans(SLSB)、Message Driven Beans(MDB)到 EJB3,而 Container-Managed Persistence(CMP)和 Bean-Managed Persistence(BMP)Entity Beans 则按照 EJB3 规格使用 Java Persistence API(JPA) 。JBoss EAP 6 里的默认容器配置包含几个对 EJB2 CMP Bean 的修改:- 默认情况下悲观锁是活动的。这可能导致死锁。
- JBoss EAP 6 里不再有 JBoss EAP 5.x 里的 CMP 层的死锁检测代码。
在 JBoss EAP 5.x 里,我们也可以在定义缓存、池、commit-options和拦截器栈。而在 JBoss EAP 6 里这是不可能的,它只有一个类似于带有commit-optionC的Instance Per Transaction策略的实现。如果您移植使用了cmp2.x jdbc2 pmentity bean 容器配置的应用程序(使用了兼容 CMP2.x 的基于 JDBC 持久化管理者 ),这会对性能有影响。这个容器为性能作了优化。我们推荐您在移植应用程序之前将这些实体移植到 EJB3。 - 服务器端连接器的配置
- JBoss EAP 6 支持使用
@Interceptors和@AroundInvoke注解的标准 Java EEInterceptor。然而,这并不会允许安全性或事务之外的操作。在以前的 JBoss EAP 版本里,我们可以修改拦截器栈为每个 EJB 调用定制拦截器。这通常用来实现自定义的安全性或安全检查、事务检查或创建前的重试机制。JBoss EAP 6.1 引入了容器拦截器来提供类似的功能。关于容器拦截器的更多信息,请参考《JBoss EAP 开发指南》里的『容器拦截器』章节。在事务的提交阶段之前、期间、之后提供更多控制且遵循 Java EE 规格的方法是使用事务同步注册表(Transaction Synchronization Registry)来添加 listener。资源可以用下列方法之一来获取:回调 Routine 必需实现- 使用
InitialContextTransactionSynchronizationRegistry tsr = (TransactionSynchronizationRegistry) new InitialContext().lookup("java:jboss/TransactionSynchronizationRegistry"); tsr.registerInterposedSynchronization(new MyTxCallback()); - 使用注入
@Resource(mappedName = "java:comp/TransactionSynchronizationRegistry") TransactionSynchronizationRegistry tsr; ... tsr.registerInterposedSynchronization(new MyTxCallback());
javax.transaction.Synchronization接口。请在事务提交或回滚前用beforeCompletion{}方法来执行任何检查。如果这个方法抛出RuntimeException,事务会被回滚且用EJBTransactionRolledbackException通知客户。如果是 XA-Transaction,所有的资源将按照 XA 合约回滚。我们也可以根据事务状态用afterCompletion(int txStatus)方法启用商业逻辑。如果这个方法抛出RuntimeException,事务将保持之前的状态,提交或回滚,且客户不会得到通知。只有事务管理者会在服务器日志文件里显示一个警告信息。 - 客户端拦截器的服务器端配置
- 在以前的 JBoss EAP 版本里,我们可以在服务器配置文件里配置客户拦截器并只提供带有客户 API 的类。在 JBoss EAP 6 里这已不可能了,因为服务器端不会再创建客户代理并再查找后传输到客户端。这个代理现在是在客户端生成。这次优化避免了查找和类上传时对服务器的调用。
- Entity Bean 池配置
- 我们不推荐在 JBoss EAP 6 里进行 Entity bean 的池配置。因为它受限于
<strict-max-pool>元素的配置,如果池过小而无法加载结果集里的所有实体,死锁和其他问题就可能发生。Entity Bean 在初始化时没有大型的生命周期方法,所以创建实例和使用容器并不会比池化的 Entity Bean 实例慢。 - 替换 jboss.xml 部署描述符文件
jboss-ejb3.xml部署描述符文件替换jboss.xml以覆盖和添加 Java EE 定义的ejb-jar.xml里提供的功能。这个新文件和jboss.xml兼容,而目前的部署里已经忽略了jboss.xml。例如,在以前的 JBoss EAP 版本里,如果您在ejb-jar.xml文件里定义了<resource-ref>,jboss.xml里的 JNDI 名称需要有对应的资源定义。XDoclet 自动生成这两个部署描述符文件。在 JBoss EAP 6,jboss-ejb3.xml文件里现在已定义了 JNDI 映射信息。我们假定 Java 源代码里的数据源是如下这样定义的。DataSource ds1 = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/Resource1"); DataSource ds2 = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/Resource2");ejb-jar.xml定义了下列资源引用。<resource-ref > <res-ref-name>jdbc/Resource1</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> <resource-ref > <res-ref-name>java:comp/env/jdbc/Resource2</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>jboss-ejb3.jxml文件用下列 XML 语法映射 JNDI 名称和引用<resource-ref> <res-ref-name>jdbc/Resource1</res-ref-name> <jndi-name>java:jboss/datasources/ExampleDS</jndi-name> </resource-ref> <resource-ref> <res-ref-name>java:comp/env/jdbc/Resource2</res-ref-name> <jndi-name>java:jboss/datasources/ExampleDS</jndi-name> </resource-ref>JBoss EAP 6 没有实现 JBoss EAP 5.xjboss.xml文件里可用的一些配置选项。下表描述了jboss.xml文件里常用的属性以及在 JBoss EAP 6 是否有替代的方法。method-attribute元素用来配置单独的 Entity 和 Session Bean 方法。read-only和idempotent配置选项没有移植到 JBoss EAP 6 里。transaction-timeout选项现在在jboss-ejb3.xml文件里进行配置。
missing-method-permission-exclude-mode属性修改了方法的行为,而不用实现 secured bean 上的显性安全元数据。在 JBoss EAP 6 里,@PermitAll注解也会依据和@RolesAllowed注解类似的方式处理。
- 数据源类型映射配置
- 在以前的 JBoss EAP 版本里,我们可以在
*-ds.xml数据源部署配置文件里配置数据源的类型映射。在 JBoss EAP 6 里,这必须在jbosscmp-jdbc.xml部署描述符文件里进行。<defaults> <datasource-mapping>mySQL</datasource-mapping> <create-table>true</create-table> .... </defaults>在以前的 JBoss EAP 版本里,自定义的映射是在standardjbosscmp-jdbc.xml文件里完成的。这个文件已取消,现在映射是通过jbosscmp-jdbc.xml部署描述符文件进行的。
其他 Container-Managed Persistence (CMP) 和 Container-Managed Relationship (CMR) 的修改
- Container Managed Relationship (CMR) Iterator 和 Collection 的修改
- 在以前的 JBoss EAP 版本里,一些容器如
cmp2.x jdbc2 pm可以迭代 CMR 容器并删除或添加关系。JBoss EAP 6 不支持这种容器配置,所以无法再这样做了。关于如何在程序代码实现相同功能的信息,请参考客户门户的『Support Knowledgebase Solutions』部分的 EJB2.1 Finder for CMP entities with relations (CMR) returns duplicates in EAP6。 - 用于 Finder 的 Container Managed Relationship (CMR) 重复条目
- 在以前的 JBoss EAP 版本里,我们可以选择使用了不同持久化策略的 CMP 容器。JBoss EAP 5.x 里的
cmp2.x jdbc2 pm容器使用优化的SQL-92来为 Finder 生成优化的 LEFT OUTER JOIN 语法。因为 JBoss EAP 6.x 只支持标准的 CMP 和 CMR 容器,其实现没有包含这些优化。Finder 应该在SELECT语句里包含关键字DISTINCT来避免结果集出现笛卡尔集合。更多的信息请参考客户门户的『Support Knowledgebase Solutions』部分的 EJB2.1 Finder for CMP entities with relations (CMR) returns duplicates in EAP6。 - 对 CMP Entity Beans 的 Cascade Delete 默认值的修改
- Cascade Delete 的默认值已改成
false。这可能导致 JBoss EAP 6 里出现删除失败。如果实体关系被标记为cascade-delete,您必须在jbosscmp-jdbc.xml文件里显性地设置batch-cascade-delete为true。更多的信息请参考客户门户的『Support Knowledgebase Solutions』部分的 cascade delete fail for EJB2 CMP Entities after migration to EAP6。 - 用于自定义字段的 CMP 自定义映射器
- 如果您的 JBoss EAP 5.x 应用程序里使用了自定义的映射器类,如
JDBCParameterSetter、JDBCResultSetReader和Mapper,在部署到 JBoss EAP 6 里时,您可能会看到java.lang.ClassNotFoundException。这是因为这些接口的软件包名从org.jboss.ejb.plugins.cmp.jdbc.Mapper改成了org.jboss.as.cmp.jdbc.Mapper。更多的信息请参考客户门户的『Support Knowledgebase Solutions』部分的 How to use Field mapping for custom classes in an EJB2 CMP application in EAP6。 - 使用 entity-commands 生成主键
- 如果您的 JBoss EAP 5 应用程序使用了
entity-commands来生成主键,如Sequence或Auto-increment,当移植应用程序到 JBoss EAP 6 时,您可以看到JDBCOracleSequenceCreateCommand抛出ClassNotFoundException。这是因为类软件包从org.jboss.ejb.plugins.cmp.jdbc改成了org.jboss.as.cmp.jdbc.keygen。如果您在 JBoss EAP 6 应用程序里使用了这个类,您必须添加对EAP_HOME/modules/system/layers/base/org/jboss/as/cmp模块的依赖关系。
应用程序的修改
- 修改代码以使用新的 JNDI 命名空间规则。
- 和 EJB 3.0 一样,对 EJB 2.x 您必须使用完整的 JNDI 前缀。关于新的 JNDI 命名空间规则和代码示例,请参考 第 3.1.8.1 节 “更新应用程序 JNDI 命名空间的名称”。关于如何更新以前版本的 JNDI 命名空间的例子,您可以参考 第 3.1.8.5 节 “以前版本的 JNDI 命名空间示例和它们在 JBoss EAP 6 里是如何指定的”。
- 修改
jboss-web.xml文件描述符 - 对每个
<ejb-ref>的<jndi-name>进行修改以使用新的 JNDI 全限定查找格式。 - 使用 XDoclet 来映射内部 Local 接口的 JNDI 名称
- 对于 EJB2,使用
Locator模式来查找 Bean 是非常常见的。如果您在程序里使用了这个模式,不需要修改代码,您可以使用 XDoclet 来生成新 JNDI 名称的映射。典型的 XDoclet 注解类似于:@ejb.bean name="UserAttribute" display-name="UserAttribute" local-jndi-name="ejb21/UserAttributeEntity" view-type="local" type="CMP" cmp-version="2.x" primkey-field="id"
上述例子里的 JNDI 名称ejb21/UserAttributeEntity在 JBoss EAP 6 里不再有效。您可以用服务器配置和 XDoclet 补丁里的naming子系统将这个名称映射到有效的 JNDI 名称。如上面的『用于自定义字段的 CMP 自定义映射器』里说提及的,您可以创建自定义的映射器,或者您可以按照下面过程描述的那样修改代码。过程 3.24. 修改 XDoclet Generated Code 并使用 Naming 子系统
- 解压
ejb-module.jar里的 XDocletlookup.xdt末班并修改lookupHome里的lookup():private static Object lookupHome(java.util.Hashtable environment, String jndiName, Class narrowTo) throws javax.naming.NamingException { // Obtain initial context javax.naming.InitialContext initialContext = new javax.naming.InitialContext(environment); try { // Replace the existing lookup // Object objRef = initialContext.lookup(jndiName); // This is the new mapped lookup Object objRef; try { // try JBoss EAP mapping objRef = initialContext.lookup("global/"+jndiName); } catch(java.lang.Exception e) { objRef = initialContext.lookup(jndiName); } // only narrow if necessary if (java.rmi.Remote.class.isAssignableFrom(narrowTo)) return javax.rmi.PortableRemoteObject.narrow(objRef, narrowTo); else return objRef; } finally { initialContext.close(); } } - 运行 Ant,对于
ejbdoclet任务设置 template 属性以使用改动的lookup.xdt。 - 修改服务器配置文件里的
naming子系统来映射旧的 JNDI 名称到新的有效 JNDI 名称。<subsystem xmlns="urn:jboss:domain:naming:1.2"> <bindings> <lookup name="java:global/ejb21/UserAttributeEntity" lookup="java:global/ejb2CMP/ejb/UserAttribute!de.wfink.ejb21.cmp.cmr.UserAttributeLocalHome"/> </bindings> <remote-naming/> </subsystem>
废弃的文件概述
JBoss EAP 6 不再支持下列文件。
- jboss.xml
- Jboss EAP 6 不再支持
jboss.xml部署描述符文件且没有在部署归档里包含它。 - standardjbosscmp-jdbc.xml
- Jboss EAP 6 不再支持
standardjbosscmp-jdbc.xml配置文件。这个配置信息现在包含在org.jboss.as.cmp模块里且不再是可以定制的了。 - standardjboss.xml
- JBoss EAP 6 不再支持
standardjboss.xml配置文件。运行独立服务器时配置信息现在包含在standalone.xml文件里,而运行在受管域时包含在domain.xml文件里。

Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.