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>
Copy to Clipboard Toggle word wrap
它也包含 cmp 子系统:
<profiles>
    ...
    <subsystem xmlns="urn:jboss:domain:cmp:1.1"/>
    ...
</profiles>
Copy to Clipboard Toggle word wrap
.
要用 Full 配置集启动 JBoss EAP 6 独立服务器,在用命令行启动服务器时请使用 -c standalone-full.xml or -c standalone-full-ha.xml 参数。
容器配置不再被支持了
在以前的 JBoss EAP 版本里,我们可以为 CMP 实体和其他 bean 配置不同的容器并通过在 jboss.xml 部署描述符文件里设置引用来使用它。例如,对于 SLSB 对 Session Bean 的引用通常有不同的配置。
在 JBoss EAP 6.x 里,我们可以将 EJB 2 Entity Bean 和标准容器一起使用。
JBoss EAP 6 里的默认容器配置包含几个对 EJB2 CMP Bean 的修改:
  • 默认情况下悲观锁是活动的。这可能导致死锁。
  • JBoss EAP 6 里不再有 JBoss EAP 5.x 里的 CMP 层的死锁检测代码。
在 JBoss EAP 5.x 里,我们也可以在定义缓存、池、commit-options 和拦截器栈。而在 JBoss EAP 6 里这是不可能的,它只有一个类似于带有 commit-option CInstance Per Transaction 策略的实现。如果您移植使用了 cmp2.x jdbc2 pm entity bean 容器配置的应用程序(使用了兼容 CMP2.x 的基于 JDBC 持久化管理者 ),这会对性能有影响。这个容器为性能作了优化。我们推荐您在移植应用程序之前将这些实体移植到 EJB3。
服务器端连接器的配置
JBoss EAP 6 支持使用 @Interceptors@AroundInvoke 注解的标准 Java EE Interceptor。然而,这并不会允许安全性或事务之外的操作。
在以前的 JBoss EAP 版本里,我们可以修改拦截器栈为每个 EJB 调用定制拦截器。这通常用来实现自定义的安全性或安全检查、事务检查或创建前的重试机制。JBoss EAP 6.1 引入了容器拦截器来提供类似的功能。关于容器拦截器的更多信息,请参考《JBoss EAP 开发指南》里的『容器拦截器』章节。
在事务的提交阶段之前、期间、之后提供更多控制且遵循 Java EE 规格的方法是使用事务同步注册表(Transaction Synchronization Registry)来添加 listener。
资源可以用下列方法之一来获取:
  • 使用 InitialContext
    TransactionSynchronizationRegistry tsr = (TransactionSynchronizationRegistry) 
    		new InitialContext().lookup("java:jboss/TransactionSynchronizationRegistry");
    tsr.registerInterposedSynchronization(new MyTxCallback());
    
    Copy to Clipboard Toggle word wrap
  • 使用注入
    @Resource(mappedName = "java:comp/TransactionSynchronizationRegistry")
    TransactionSynchronizationRegistry tsr;
    ...
    tsr.registerInterposedSynchronization(new MyTxCallback());
    
    Copy to Clipboard Toggle word wrap
回调 Routine 必需实现 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");
Copy to Clipboard Toggle word wrap
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>
Copy to Clipboard Toggle word wrap
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>
Copy to Clipboard Toggle word wrap
JBoss EAP 6 没有实现 JBoss EAP 5.x jboss.xml 文件里可用的一些配置选项。下表描述了 jboss.xml 文件里常用的属性以及在 JBoss EAP 6 是否有替代的方法。
  • method-attribute 元素用来配置单独的 Entity 和 Session Bean 方法。
    • read-onlyidempotent 配置选项没有移植到 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>
Copy to Clipboard Toggle word wrap
在以前的 JBoss EAP 版本里,自定义的映射是在 standardjbosscmp-jdbc.xml 文件里完成的。这个文件已取消,现在映射是通过 jbosscmp-jdbc.xml 部署描述符文件进行的。
其他 Container-Managed Persistence (CMP) 和 Container-Managed Relaationship(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-deletetrue。更多的信息请参考客户门户的『Support Knowledgebase Solutions』部分的 cascade delete fail for EJB2 CMP Entities after migration to EAP6
用于自定义字段的 CMP 自定义映射器
如果您的 JBoss EAP 5.x 应用程序里使用了自定义的映射器类,如 JDBCParameterSetterJDBCResultSetReaderMapper,在部署到 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 来生成主键,如 SequenceAuto-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"
Copy to Clipboard Toggle word wrap
上述例子里的 JNDI 名称 ejb21/UserAttributeEntity 在 JBoss EAP 6 里不再有效。您可以用服务器配置和 XDoclet 补丁里的 naming 子系统将这个名称映射到有效的 JNDI 名称。
如上面的『用于自定义字段的 CMP 自定义映射器』里说提及的,您可以创建自定义的映射器,或者您可以按照下面过程描述的那样修改代码。

过程 3.24. 修改 XDoclet Generated Code 并使用 Naming 子系统

  1. 解压 ejb-module.jar 里的 XDoclet lookup.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();  
        }  
    }
    Copy to Clipboard Toggle word wrap
  2. 运行 Ant,对于 ejbdoclet 任务设置 template 属性以使用改动的 lookup.xdt
  3. 修改服务器配置文件里的 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>
    
    Copy to Clipboard Toggle word wrap
废弃的文件概述

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 文件里。
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat