- 浏览: 269382 次
- 性别:
- 来自: 新乡
文章分类
- 全部博客 (227)
- servciemix (10)
- db (18)
- javaTools (4)
- hibernate (31)
- web (3)
- spring (14)
- design pattern (4)
- java security (3)
- portal (1)
- ejb (6)
- session (2)
- java_lang (21)
- jbpm (29)
- struts (7)
- orgRights (2)
- project manager Jira (7)
- 跨库事务 (2)
- mysql (14)
- ubuntu (7)
- osgi (9)
- maven ant make (4)
- 分布式 高并发 高性能 (5)
- virgo-dm_server (0)
- osgi web (3)
- platform (1)
- smooks (1)
- business (1)
- 职场生涯 (14)
- Java编码格式 (2)
- web服务 (1)
- 计算机使用 (1)
- 健康工作生活的保障,工作中务必抛掉的不良心态 (4)
- 电信-网络监控 (1)
- 多线程-multithread (1)
- 海量数据-高性能 (2)
- Mybatis (1)
- web开发平台研发 (0)
- oracle (0)
- 应用服务器调优 (0)
- web前端 (0)
- servlet-jsp (0)
- tomcat (2)
- newtouch (1)
- portal_liferay (2)
- version control (1)
- apm-impact (2)
- tools (1)
- 研发管理 (1)
- 电商业务 (1)
- 生鲜电商市场调查 (0)
- PBX (0)
- 房东 (0)
最新评论
-
lifuchao:
...
权限问题 -
Branding:
谢谢,受教了,另外,CONN AS SYSDBA,必须是在操作 ...
Oracle密码忘记了怎么办? -
zhuchao_ko:
...
Portal实现原理 -
败类斯文:
不知道改哪里。。。木有见到红色。。表示悟性低了、、
jira error: Neither the JAVA_HOME nor the JRE_HOME environment variable is defin -
c__06:
正文:假如事务我是这样定义的: <tx:method n ...
Spring中Transactional配置
权衡 Apache Geronimo EJB 事务选项,第 1 部分: 容器管理事务
了解 Geronimo 和 OpenEJB 能为您做什么
Jonathan Sagorin (jonathan@javaoncall.com), 自由软件开发人员
Jonathan Sagorin 是一位自由开发人员。在 10 年职业生涯里,他大部分时间都是一名顾问,为用户提供自定义 Java 解决方案。业余时间他尝试玩垒球和即兴表演(不必同时进行,虽然他的垒球队友不这么认为)。
简介: 本系列分为三部分,将探索 Apache Geronimo 中的 Enterprise Java™Beans (EJB) 容器管理事务和 bean 管理事务。在第 1 部分中,将找出两种事务之间的差异,其中包括了解容器管理事务如何帮助您避免事务逻辑和管理的复杂性,从而使您可以专注于企业 bean 的业务逻辑。您还将学会如何在 Geronimo 应用服务器中实现容器管理事务,以及如何使用 Geronimo、OpenEJB 和 XDoclet 将自己从繁重的 EJB 编码工作中解放出来。
查看本系列更多内容
标记本文!
发布日期: 2006 年 10 月 23 日
级别: 初级
访问情况 434 次浏览
建议: 0 (添加评论)
1 star2 stars3 stars4 stars5 stars 平均分 (共 3 个评分 )
简介
OpenEJB 是为 Apache Geronimo 选定的 EJB 容器实例。虽然 EJB 3.0 目前已经面市,但直到发布 Geronimo 2.0 版,在 Geronimo 接受 Java 1.5 认证时,Geronimo 才支持 EJB。
本系列分为三部分,将使您了解 Geronimo 和 OpenEJB 可以为您提供什么帮助,以及在 EJB 2.1 中现在可以实现的 EJB 事务概念(让您顺利进入 EJB 3.0)。
EJB 框架提供的好处是:可以使用事务,但没有事务 API 编程的痛苦。在实现 EJB 事务时,您有两种选择:
* 告诉 EJB 容器处理所有的硬性事务工作(容器管理的事务)。
* 让企业 bean 处理一部分事务工作(bean 管理的事务)。
在本系列的第 1 部分中,将从事务的概述开始,然后讨论 EJB 2.1 中描述的 EJB 容器管理的事务。最后用一些代码片断结束介绍,这些代码将显示如何在 Geronimo 应用服务器上实现容器管理的事务。
在第 2 部分中,将获得 EJB 2.1 中 bean 管理的事务的概述,并查看一些示例代码实现。
在第 3 部分中,将综合这两种事务,并了解与容器管理的事务和 bean 管理的事务有关的难题和附加特性。
事务—— 概述
什么是事务?为什么它们如此重要?可以考虑一下银行事务这个非常简单的案例:将 100 美元从您的一个活期存款帐户转移到您的储蓄存款帐户。通过进一步的调查,可将这一操作分解为两个更小的操作:
* 银行从您的活期存款帐户减去 100 美元。
* 银行在您的储蓄存款帐户增加 100 美元。
如果银行将活期存款额减少 100 美元,但您的储蓄存款额并没有增加 100 美元,那么您可能会感到有点沮丧。就个人而言,我愿意将两个操作视为一个操作。因此,如果您的储蓄存款帐户从没有增加 100 美元,那么 100 美元也决不应从您的活期存款帐户中减去!
类似地,在应用过程中,很多业务案例都是进行整体确认的 (all-or-nothing approach)。一些大的操作由一个或多个更小的步骤组成。为了完成操作,操作中的所有 步骤都必须完成或不完成,这种行为称为原子 行为。
原子性是事务必须保证的四个特征(或属性)之一。其他三个属性是:
* 一致性
* 隔离性
* 耐久性
这四种属性一起被称为 ACID 属性。
ACID 属性
事务对这些已知 ACID 属性的描述为:
* 事务是原子的。所有操作都被认为是一个工作单元。像前面讨论的那样,是整体确认的。
* 事务是一致的。在执行事务之后,必须将系统维持在一致(或合法)状态下。合法状态的定义取决于系统。根据早先的示例,在执行任何撤消操作之后,银行指示您,将保留您的活期存款帐户为顺差。
* 事务是隔离的。每个事务在同一资源进行操作时与其他事务都是相互隔离的。这可通过数据的锁同步来实现。
* 事务是持久的。资源更新必须避免系统故障,如硬件或网络故障。在分布式系统中,当出现网络故障或数据库崩溃时,恢复过程是必需的。
事务模型
有两种流行的事务模型:flat 事务和 nested 事务。EJB 支持 flat 事务模型。
flat 事务是作为单个工作单元处理的一系列操作。工作单元只有两种结果:要么成功,要么失败。如果事务中的所有步骤都成功完成,则事务获得提交,并且该操作执行的所有持久存储数据更改都将永久化。如果事务中某一步骤失败,则事务将回滚 (roll back),并反转事务中步骤受影响的所有数据。
nested 事务允许事务嵌套在其他事务中。嵌套在其他事务中的事务允许在不影响其父事务的情况下进行回滚。失败的 nested 事务可以继续重试。如果再次失败,则可回滚父事务。
回页首
EJB 事务
EJB 是用于组件开发的一个框架。您开发的 EJB 将运行在 EJB 容器中。此外,EJB 容器为事务带来了一些好处。OpenEJB 是 Geronimo 用来提供事务管理的 EJB 容器。
EJB 架构支持分布式事务。一些需要分布式事务的场景模式范例包括:
* 更新多个数据库的单个事务中的应用。
* 从 Java Message Service (JMS) 目标发送或接收消息并更新一个或多个数据库的单个事务中的应用。
* 通过多个 EJB 服务器来更新多个数据库的单个事务中的应用。
* 在更新多个 EJB 服务器上的多个数据库之前,Java 客户端明确区分事务边界。
事务边界
在实现 EJB 事务时,您将划分事务边界:谁启动事务、谁提交或中止事务,以及什么时候使用事务。这取决于 EJB 容器和服务器提供商提供的事务管理和底层事务通信协议。
有两种划分方案:
* declarative 方案,使用该方案可以将事务实现委托给 EJB 容器。(该方案是本文其余部分的焦点。)
* programmatic 方案,在该方案中,企业 bean 使用自己的代码自己提供提交或中止信息。(本系列的第 2 部分中将介绍此方案。)
在使用 declarative 事务划分时,EJB 容器根据 EJB 部署描述符中由应用程序开发人员声明的指令,在企业 bean 的方法上应用事务边界。这称为容器管理的事务。
在实现 programmatic 划分事务时,应用程序开发人员负责将事务逻辑和界线编入企业 bean 代码中。这称为 bean 管理的事务。
我应该使用哪种事务?
容器管理的事务更加简单并且在代码中不需要实现事务逻辑,无论您的企业 bean 方法是否必须运行在事务中。此外,调用 bean 的 Java 客户端不能滥用您的企业 bean,因为事务始终是有始有终的。
如果想完全控制事务边界,请使用 bean 管理的事务。该方法允许在代码中直接控制提交或控制回滚逻辑发生的地方。
会话 bean 和消息驱动 bean (MDB) 可以使用 bean 管理的事务或容器管理的事务,但是实体 bean 必须始终使用容器管理的事务。实体 bean 使用 bean 管理的持久性是不合法的。
回页首
容器管理的事务
事务划分边界是通过指令或事务属性提供的。这些属性描述了企业 bean 是如何参与到事务中的。您可以对每个 bean 指定不同的事务属性而不必考虑 bean 的数目。您可以为 bean 的个别或所有方法指定属性。方法的属性是优先于 bean 的。
回页首
会话 bean 和实体 bean 的事务属性
会话 bean 和实体 bean 可能的属性值包括:
* Required —— bean 必须始终运行在事务中。如果客户端已经启动一个事务,则 bean 将加入到事务中。如果客户端还没有启动事务,那么 EJB 容器将启动一个新事务。当需要 bean 始终运行在事务中时,请使用该属性。
* RequiresNew —— bean 始终启动一个新的事务。如果客户端已经启动一个事务,则挂起现有事务,直到新事务已提交或中止。在新事务完成之后,现有事务将继续。当需要 bean 作为一个单独的工作单元运行并展示所有的 ACID 属性时,请使用该属性。
* Supports —— 如果客户端启动一个事务,则 bean 将加入到事务中。但是,如果事务不存在,EJB 容器不会启动一个新事务。要在企业 bean 上执行非任务关键型操作时,请使用该属性。
* Mandatory —— 在调用 bean 时客户端必须启动一个事务。这不会创建一个新的事务。在调用 bean 时,如果没有事务已经启动,则将抛出一个异常。当 bean 是某一较大系统的一部分时,请使用该属性。通常可能由第三方负责启动事务。对用户而言,这是一个安全选项,因为它可以确保 bean 将成为事务的一部分。
* NotSupported —— 在事务中不能调用 bean。如果客户端已经启动一个事务,则挂起现有事务,直到 bean 的方法完成。在完成上述方法之后,现有事务将继续。如果客户端没有启动事务,则不会创建一个新事务。在不需要 bean 展示任何 ACID 属性(比如类似报表的非系统关键型操作)时,请使用该属性。
* Never —— 如果客户端启动一个事务,则 bean 将抛出一个异常。在您可能永远都不想让您的 bean 参与到事务中的情况下,请使用该属性。
回页首
消息驱动 bean 的事务属性
只有两种消息驱动 bean 消息监听器方法使用的事务属性:
* NotSupported —— bean 不能参与到事务中。如果客户端启动一个事务,那么现有事务将挂起,直到 bean 的方法完成为止。在完成上述方法之后,现有事务将继续。如果客户端没有启动事务,则不会创建一个新的事务。
* Required —— bean 必须始终运行在事务中。如果客户端已经启动事务,则 bean 将加入到事务中。如果客户端没有启动事务,则 EJB 容器将启动一个新事务。
在为企业 bean 方法确定正确事务属性之后,就可以配置 EJB 部署描述符了。
回页首
配置 EJB 部署描述符
对于每个企业 bean,都要在部署描述符中配置事务的下列两个部分:
* 在 EJB 部署描述符中使用 <transaction-type> 元素指定 bean 使用的是容器管理的事务还是 bean 管理的事务。可能的值是 container 或 bean。由于实体 bean 必须使用容器管理的事务,这只对会话 bean 和消息驱动 bean 是必需的。
* 对于容器管理的事务,您可以为企业 bean 的方法随意指定事务属性。在 EJB 部署描述符中的 <container-transaction> 部分指定它。清单 1 中显示了每种方法的通用格式。
清单 1. 每种方法的通用格式
<method>
<ejb-name>EJBNAME</ejb-name>
<method-name>METHODNAME</method-name>
<trans-attribute>TRANSATTRIBUTE</trans-attribute>
</method>
TRANSATTRIBUTE 可能的值有:
* NotSupported
* Required
* Supports
* RequiresNew
* Mandatory
* Never
也可以对企业 bean 的所有方法指定事务属性。对 <method-name> 属性使用 *。
清单 2 显示了为容器管理的企业 bean 指定事务属性的示例。除了为 updateClaimNumber 方法分配 Mandatory 属性以外,ClaimRecord企业 bean 为所有方法都分配了 Required 属性。Coverage bean 对所有方法指派 RequiresNew 属性。
清单 2. ejb 部署描述符文件中的事务属性
<ejb-jar>
...
<assembly-descriptor>
...
<container-transaction>
<method>
<ejb-name>ClaimRecord</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>ClaimRecord</ejb-name>
<method-name>updateClaimNumber</methodname>
</method>
<trans-attribute>Mandatory</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>Coverage</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
...
</assembly-descriptor>
...
</ejb-jar>
回页首
Geronimo 配置
既然您明白了在 EJB 部署描述符中指定事务属性的通用格式,那么可以考虑一下如何在 Geronimo 中使用 OpenEJB 实现这一点。在 Geronimo 中开发 EJB 时,可以通过使用 XDoclet 生成所需的大部分单调的 EJB 编程工件 (artifact) 来节省时间。作为这些工件的一部分,XDoclet 生成了 EJB 部署描述符。
作为正常开发过程的一部分,可以在企业 bean 中指定 JavaDoc-style 标识标签。通过在企业 bean 中声明标识标签,XDoclet 可生成 ejbjar.xml。这包括属性定义的任何事务。您不用自己直接编译部署描述符 (ejb-jar.xml)。
在 XDoclet 中使用 @ejb.transaction 标识指定事务属性。在需要使用它时,可以在企业 bean 的方法之上声明它。
XDoclet 配置示例和 ejbjar.xml 生成
下面的代码片断显示了一个简洁的会话 bean 和实体 bean 示例,然后由 XDoclet 生成最终的 ejbjar.xml 文件。首先,清单 3 显示了一个名为 SampleSession 的无状态会话 bean。只需要注意与事务相关的部分即可(用粗体显示)。
清单 3. 会话 bean
package org.my.package.ejb;
/**
* Sample session bean.
* Declare all my XDoclet tags here
* ...
* ...
* @ejb.bean name="SampleSession"
* type="Stateless"
* local-jndi-name="java:comp/env/ejb/SampleSessionLocal"
* jndi-name="org.my.package.ejb/SampleSessionLocal/Home"
* view-type="both"
*
* @ejb.permission unchecked="true"
*
* @ejb.interface generate="local,remote"
* remote-class="org.my.package.ejb.SampleSession"
* local-class=" org.my.package.ejb. SampleSession Local"
* @ejb.home generate="local, remote"
* remote-class="org.my.package.ejb.SampleSession Home"
* local-class="org.my.package.SampleSession LocalHome"
* @ejb.util generate="physical"
* ...
* ...
*/
public abstract class SampleSessionBean implements javax.ejb.SessionBean {
/**
* Perform a business operation. Add something
* @param someParam the value
* @ejb.interface-method view-type="both"
* @ejb.transaction type="Required"
*/
public void doSomething(java.lang.String someParam)) {
...
}
/*
* Perform another business operation. Add something
* @param someParam the value
* @ejb.interface-method view-type="both"
* @ejb.transaction type="RequiresNew"
*/
public void doSomethingElse(java.lang.String someParam)) {
...
}
/**
* @ejb.create-method
* @ejb.transaction type="Required"
*/
public void ejbCreate ()
throws javax.ejb.CreateException
{
}
public void ejbPostCreate ()
throws javax.ejb.CreateException
{
}
protected javax.ejb.SessionContext _ctx = null;
public void setSessionContext( javax.ejb.SessionContext ctx )
{
_ctx = ctx;
}
protected javax.ejb.SessionContext getSessionContext()
{
return _ctx;
}
}
同样的标识 @ejb.transaction 被用来指定该实体 bean 的事务属性。清单 4 显示如何指定实体 bean 的事务属性。同样,只需要注意粗体的标识即可。
清单 4. 实体 bean
package org.my.package.ejb;
/**
*
* @ejb.bean
* type="CMP"
* cmp-version="2.x"
* name="ClaimEntry"
* local-jndi-name="org.my.package.ejb/ClaimLocalHome"
* view-type="local"
* primkey-field="name"
*
*
* @xx-ejb.data-object
* container="true"
* setdata="true"
* generate="true"
*
* @ejb.value-object
*
* @ejb.transaction type="Required"
* @ejb.permission unchecked="true"
* @struts.form include-all="true"
*
* @web.ejb-local-ref
* name="ejb/ClaimLocal"
* type="Entity"
* home="org.my.package.ejb.ClaimLocalHome"
* local="org.my.package.ejb.ClaimLocal"
* link="PhoneBookEntry"
*
* @ejb.persistence table-name="Claim"
*
*/
public abstract class ClaimBean
implements javax.ejb.EntityBean
{
* ... EJB entity bean implementation here
}
在编译过程中执行 XDoclet 时,生成了 ejb-jar.xml。清单5 显示了文件的事务相关部分。注意粗体显示的 <transaction-type> 和 <trans-attribute> 元素。
清单 5. 生成的 ejb-jar.xml 片断
...
<ejb-jar >
<description><![CDATA[No Description.]]></description>
<display-name>Generated by XDoclet</display-name>
<enterprise-beans>
<!-- Session Beans -->
<session >
<description><![CDATA[Sample session
bean.]]></description>
<ejb-name>SampleSession</ejb-name>
<home>org.my.package.ejb.SampleSessionHome</home>
<remote>org.my.package.ejb.SampleSession</remote>
<local-home>org.my.package.ejb.SampleSessionLocalHome
</local-home>
<local>org.my.package.ejb.SampleSessionLocal</local>
<ejb-class>org.my.package.ejb.SampleSessionSessionSession
</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
...
<!-- Entity Beans -->
<entity >
<description><![CDATA[]]></description>
<ejb-name>Claim</ejb-name>
<local-home>
org.my.package.ejb.ClaimLocalHome</local-home>
<local>org.my.package.ejb.ClaimLocal</local>
<ejb-class>org.my.package.ejb.ClaimCMP</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>Claim</abstract-schema-name>
...
</entity>
...
<container-transaction >
<method >
<ejb-name>Claim</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Local</method-intf>
<method-name>doSomething</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Remote</method-intf>
<method-name>doSomething</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Local</method-intf>
<method-name>doSomethingElse</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Remote</method-intf>
<method-name>doSomethingElse</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
...
</ejb-jar>
事务同步
容器管理的事务允许 EJB 容器指定事务边界,这可以简化您的工作。然而,当事务中止时,可能需要执行一些 bean 状态的恢复工作。对于无状态会话 bean,可能抛出一个简单的异常。有状态会话 bean 表示了对话状态(或商业流程),这可能会跨越几个 bean 方法调用。
如果要求有状态会话 bean 获得事务边界状态事件通知,则需要编写企业 bean 代码来实现可选的 javax.ejb.SessionSynchronization 接口。您必须实现定义在接口上的下列方法:
* afterBegin() —— 在新事务启动之后但在调用业务方法之前通知会话 bean。在事务提交之前,bean 实例可以做任何它所需要的数据库读取操作。在缓冲事务所需要的数据时,这很有用。
* beforeCompletion() —— 在业务方法完成之后但是在事务提交之前通知会话 bean。如果有任何缓冲数据,可以将其更新到数据库中。bean 还可以在会话上下文中通过调用 setRollBackOnly() 执行事务的手动回滚。
* afterCompletion(boolean committed) —— 在事务提交之后通知会话 bean。提交的布尔值指出是提交事务还是中止事务。如果该值为 true,则事务成功获得提交。如果该值为 false,则事务中止。因此,bean 的对话状态/实例变量可以被恢复或重新设置。
避免使用的方法
既然 EJB 容器是负责控制事务边界,那么您不应该调用任何可能干涉容器边界划分的方法。如果您正在实现容器管理的事务,请确保企业 bean 方法不会调用下列方法:
* java.sql.Connection 的 commit、setAutoCommit 和 rollback 方法
* javax.ejb.EJBContext 的 getUserTransaction 方法
* javax.transaction.UserTransaction 的任何方法
回滚
在某些情况下您可能需要明确中止事务。有两种回滚容器管理的事务的方式:
* 让容器自动回滚事务。如果有任何企业 bean 抛出的运行时异常,就会发生这种回滚。
* 调用 EJBContext 接口的 setRollBackOnly() 方法。在发生回滚时,允许您进行控制。或许由于一些有效性验证失败或存在数据完整性问题,您可能需要回滚整个事务并抛出一个应用程序异常。应用程序异常不会自动导致容器回滚一个异常。
回页首
结束语
在本系列的第 1 部分,简单介绍了事务和 EJB 事务的两个选择。您可以看到容器管理的事务如何使您专注于您的企业 bean 的业务逻辑,而将事务逻辑和管理的复杂性留给 EJB 容器。
使用容器管理的事务,您只需要关心企业 bean 如何参与到事务中,并通过 EJB 部署描述符的简单配置来实现这一点。Geronimo 应用服务器、OpenEJB 和 XDoclet 将帮助您简化如何指定容器管理的设置,并将您从繁重的 EJB 工件编码工作中解放出来。
继续关注本系列的第 2 部分,您将了解 bean 管理的事务,在第 3 部分中,我们会将二者综合使用。
参考资料
学习
* 阅读 “利用 Geronimo 深入 EJB Web 应用程序”(developerWorks,2005 年 7 月),了解如何在 Geronimo 中使用 EJB。
* 通过 “在 Apache Geronimo 上部署 J2EE 应用程序”(developerWorks,2006 年 1 月)了解如何部署 JavaServer Pages (JSP)、servlet 和 Apache Geronimo 上的不同 EJB。
* 查看 Dale Green 的文章 “Enterprise Beans”,获得关于 Geronimo 中部署描述符的更多信息。
* 阅读更多有关 Sun 公司的 EJB 规范 的信息。
* 学习有关 XDoclet 的更多信息。
* 阅读 Nicholas Chase 与 David Blevins(OpenEJB 的共同创始人)的访谈 “Geronimo 叛逆者:OpenEJB 和 Apache Geronimo 的 EJB 实现”(developerWorks,2006 年 5 月),了解 OpenEJB 是如何被选为 Geronimo 的 EJB 实现的。
* 加入 Apache Geronimo 网站的 邮件列表。
* 阅读 “构建更佳的 J2EE 服务器,开源之路”(developerWorks,2005 年 5 月),获得有关 Geronimo 背后的开发过程的重要信息,包括其 JSR-88 支持。
* 查看 developerWorks Apache Geronimo 项目专区,获得有助于您现在使用 Geronimo 开始开发的文章、教程和其他参考资料。
* 在 developerWorks 的 现在开始学习 Apache Geronimo 部分查找对于初学者和有经验的用户有用的参考资料。
* 查看提供的 IBM Support for Apache Geronimo,它会使您在开发 Geionimo 应用程序时得到世界级的 IBM 支持。
* 访问 developerWorks 开放源码专区,从那里可以获得大量的 how-to 信息、工具和项目更新,这些有助于您使用开放源码技术进行开发,并将这些技术 IBM 产品结合使用。
* 在 “developerWorks 开放源码专区” 上浏览所有可获得的 Apache 文章 和 免费 Apache 教程。
* 浏览 Safari bookstore 上的有关书籍和其他技术主题。
获得产品和技术
* 下载 Apache Geronimo, Version 1.0。
* 使用 IBM 试用软件 改进您的下一个开放源码开发项目,可以通过下载或从 DVD 中获得这些软件。
* 下载 IBM WebSphere® Application Server Community Edition V1.0 的免费副本 —— 它是一个轻量级的 J2EE 应用服务器,使用 Apache Geronimo 开放源码技术构建而成,用于帮助您加速开发和部署工作。
讨论
* 参与论坛讨论。
* 与 Apache Geronimo blog 上的 Geronimo 开发保持同步。
* 通过参与 developerWorks blogs 加入 developerWorks 社区。
关于作者
Jonathan Sagorin 是一位自由开发人员。在 10 年职业生涯里,他大部分时间都是一名顾问,为用户提供自定义 Java 解决方案。业余时间他尝试玩垒球和即兴表演(不必同时进行,虽然他的垒球队友不这么认为)。
了解 Geronimo 和 OpenEJB 能为您做什么
Jonathan Sagorin (jonathan@javaoncall.com), 自由软件开发人员
Jonathan Sagorin 是一位自由开发人员。在 10 年职业生涯里,他大部分时间都是一名顾问,为用户提供自定义 Java 解决方案。业余时间他尝试玩垒球和即兴表演(不必同时进行,虽然他的垒球队友不这么认为)。
简介: 本系列分为三部分,将探索 Apache Geronimo 中的 Enterprise Java™Beans (EJB) 容器管理事务和 bean 管理事务。在第 1 部分中,将找出两种事务之间的差异,其中包括了解容器管理事务如何帮助您避免事务逻辑和管理的复杂性,从而使您可以专注于企业 bean 的业务逻辑。您还将学会如何在 Geronimo 应用服务器中实现容器管理事务,以及如何使用 Geronimo、OpenEJB 和 XDoclet 将自己从繁重的 EJB 编码工作中解放出来。
查看本系列更多内容
标记本文!
发布日期: 2006 年 10 月 23 日
级别: 初级
访问情况 434 次浏览
建议: 0 (添加评论)
1 star2 stars3 stars4 stars5 stars 平均分 (共 3 个评分 )
简介
OpenEJB 是为 Apache Geronimo 选定的 EJB 容器实例。虽然 EJB 3.0 目前已经面市,但直到发布 Geronimo 2.0 版,在 Geronimo 接受 Java 1.5 认证时,Geronimo 才支持 EJB。
本系列分为三部分,将使您了解 Geronimo 和 OpenEJB 可以为您提供什么帮助,以及在 EJB 2.1 中现在可以实现的 EJB 事务概念(让您顺利进入 EJB 3.0)。
EJB 框架提供的好处是:可以使用事务,但没有事务 API 编程的痛苦。在实现 EJB 事务时,您有两种选择:
* 告诉 EJB 容器处理所有的硬性事务工作(容器管理的事务)。
* 让企业 bean 处理一部分事务工作(bean 管理的事务)。
在本系列的第 1 部分中,将从事务的概述开始,然后讨论 EJB 2.1 中描述的 EJB 容器管理的事务。最后用一些代码片断结束介绍,这些代码将显示如何在 Geronimo 应用服务器上实现容器管理的事务。
在第 2 部分中,将获得 EJB 2.1 中 bean 管理的事务的概述,并查看一些示例代码实现。
在第 3 部分中,将综合这两种事务,并了解与容器管理的事务和 bean 管理的事务有关的难题和附加特性。
事务—— 概述
什么是事务?为什么它们如此重要?可以考虑一下银行事务这个非常简单的案例:将 100 美元从您的一个活期存款帐户转移到您的储蓄存款帐户。通过进一步的调查,可将这一操作分解为两个更小的操作:
* 银行从您的活期存款帐户减去 100 美元。
* 银行在您的储蓄存款帐户增加 100 美元。
如果银行将活期存款额减少 100 美元,但您的储蓄存款额并没有增加 100 美元,那么您可能会感到有点沮丧。就个人而言,我愿意将两个操作视为一个操作。因此,如果您的储蓄存款帐户从没有增加 100 美元,那么 100 美元也决不应从您的活期存款帐户中减去!
类似地,在应用过程中,很多业务案例都是进行整体确认的 (all-or-nothing approach)。一些大的操作由一个或多个更小的步骤组成。为了完成操作,操作中的所有 步骤都必须完成或不完成,这种行为称为原子 行为。
原子性是事务必须保证的四个特征(或属性)之一。其他三个属性是:
* 一致性
* 隔离性
* 耐久性
这四种属性一起被称为 ACID 属性。
ACID 属性
事务对这些已知 ACID 属性的描述为:
* 事务是原子的。所有操作都被认为是一个工作单元。像前面讨论的那样,是整体确认的。
* 事务是一致的。在执行事务之后,必须将系统维持在一致(或合法)状态下。合法状态的定义取决于系统。根据早先的示例,在执行任何撤消操作之后,银行指示您,将保留您的活期存款帐户为顺差。
* 事务是隔离的。每个事务在同一资源进行操作时与其他事务都是相互隔离的。这可通过数据的锁同步来实现。
* 事务是持久的。资源更新必须避免系统故障,如硬件或网络故障。在分布式系统中,当出现网络故障或数据库崩溃时,恢复过程是必需的。
事务模型
有两种流行的事务模型:flat 事务和 nested 事务。EJB 支持 flat 事务模型。
flat 事务是作为单个工作单元处理的一系列操作。工作单元只有两种结果:要么成功,要么失败。如果事务中的所有步骤都成功完成,则事务获得提交,并且该操作执行的所有持久存储数据更改都将永久化。如果事务中某一步骤失败,则事务将回滚 (roll back),并反转事务中步骤受影响的所有数据。
nested 事务允许事务嵌套在其他事务中。嵌套在其他事务中的事务允许在不影响其父事务的情况下进行回滚。失败的 nested 事务可以继续重试。如果再次失败,则可回滚父事务。
回页首
EJB 事务
EJB 是用于组件开发的一个框架。您开发的 EJB 将运行在 EJB 容器中。此外,EJB 容器为事务带来了一些好处。OpenEJB 是 Geronimo 用来提供事务管理的 EJB 容器。
EJB 架构支持分布式事务。一些需要分布式事务的场景模式范例包括:
* 更新多个数据库的单个事务中的应用。
* 从 Java Message Service (JMS) 目标发送或接收消息并更新一个或多个数据库的单个事务中的应用。
* 通过多个 EJB 服务器来更新多个数据库的单个事务中的应用。
* 在更新多个 EJB 服务器上的多个数据库之前,Java 客户端明确区分事务边界。
事务边界
在实现 EJB 事务时,您将划分事务边界:谁启动事务、谁提交或中止事务,以及什么时候使用事务。这取决于 EJB 容器和服务器提供商提供的事务管理和底层事务通信协议。
有两种划分方案:
* declarative 方案,使用该方案可以将事务实现委托给 EJB 容器。(该方案是本文其余部分的焦点。)
* programmatic 方案,在该方案中,企业 bean 使用自己的代码自己提供提交或中止信息。(本系列的第 2 部分中将介绍此方案。)
在使用 declarative 事务划分时,EJB 容器根据 EJB 部署描述符中由应用程序开发人员声明的指令,在企业 bean 的方法上应用事务边界。这称为容器管理的事务。
在实现 programmatic 划分事务时,应用程序开发人员负责将事务逻辑和界线编入企业 bean 代码中。这称为 bean 管理的事务。
我应该使用哪种事务?
容器管理的事务更加简单并且在代码中不需要实现事务逻辑,无论您的企业 bean 方法是否必须运行在事务中。此外,调用 bean 的 Java 客户端不能滥用您的企业 bean,因为事务始终是有始有终的。
如果想完全控制事务边界,请使用 bean 管理的事务。该方法允许在代码中直接控制提交或控制回滚逻辑发生的地方。
会话 bean 和消息驱动 bean (MDB) 可以使用 bean 管理的事务或容器管理的事务,但是实体 bean 必须始终使用容器管理的事务。实体 bean 使用 bean 管理的持久性是不合法的。
回页首
容器管理的事务
事务划分边界是通过指令或事务属性提供的。这些属性描述了企业 bean 是如何参与到事务中的。您可以对每个 bean 指定不同的事务属性而不必考虑 bean 的数目。您可以为 bean 的个别或所有方法指定属性。方法的属性是优先于 bean 的。
回页首
会话 bean 和实体 bean 的事务属性
会话 bean 和实体 bean 可能的属性值包括:
* Required —— bean 必须始终运行在事务中。如果客户端已经启动一个事务,则 bean 将加入到事务中。如果客户端还没有启动事务,那么 EJB 容器将启动一个新事务。当需要 bean 始终运行在事务中时,请使用该属性。
* RequiresNew —— bean 始终启动一个新的事务。如果客户端已经启动一个事务,则挂起现有事务,直到新事务已提交或中止。在新事务完成之后,现有事务将继续。当需要 bean 作为一个单独的工作单元运行并展示所有的 ACID 属性时,请使用该属性。
* Supports —— 如果客户端启动一个事务,则 bean 将加入到事务中。但是,如果事务不存在,EJB 容器不会启动一个新事务。要在企业 bean 上执行非任务关键型操作时,请使用该属性。
* Mandatory —— 在调用 bean 时客户端必须启动一个事务。这不会创建一个新的事务。在调用 bean 时,如果没有事务已经启动,则将抛出一个异常。当 bean 是某一较大系统的一部分时,请使用该属性。通常可能由第三方负责启动事务。对用户而言,这是一个安全选项,因为它可以确保 bean 将成为事务的一部分。
* NotSupported —— 在事务中不能调用 bean。如果客户端已经启动一个事务,则挂起现有事务,直到 bean 的方法完成。在完成上述方法之后,现有事务将继续。如果客户端没有启动事务,则不会创建一个新事务。在不需要 bean 展示任何 ACID 属性(比如类似报表的非系统关键型操作)时,请使用该属性。
* Never —— 如果客户端启动一个事务,则 bean 将抛出一个异常。在您可能永远都不想让您的 bean 参与到事务中的情况下,请使用该属性。
回页首
消息驱动 bean 的事务属性
只有两种消息驱动 bean 消息监听器方法使用的事务属性:
* NotSupported —— bean 不能参与到事务中。如果客户端启动一个事务,那么现有事务将挂起,直到 bean 的方法完成为止。在完成上述方法之后,现有事务将继续。如果客户端没有启动事务,则不会创建一个新的事务。
* Required —— bean 必须始终运行在事务中。如果客户端已经启动事务,则 bean 将加入到事务中。如果客户端没有启动事务,则 EJB 容器将启动一个新事务。
在为企业 bean 方法确定正确事务属性之后,就可以配置 EJB 部署描述符了。
回页首
配置 EJB 部署描述符
对于每个企业 bean,都要在部署描述符中配置事务的下列两个部分:
* 在 EJB 部署描述符中使用 <transaction-type> 元素指定 bean 使用的是容器管理的事务还是 bean 管理的事务。可能的值是 container 或 bean。由于实体 bean 必须使用容器管理的事务,这只对会话 bean 和消息驱动 bean 是必需的。
* 对于容器管理的事务,您可以为企业 bean 的方法随意指定事务属性。在 EJB 部署描述符中的 <container-transaction> 部分指定它。清单 1 中显示了每种方法的通用格式。
清单 1. 每种方法的通用格式
<method>
<ejb-name>EJBNAME</ejb-name>
<method-name>METHODNAME</method-name>
<trans-attribute>TRANSATTRIBUTE</trans-attribute>
</method>
TRANSATTRIBUTE 可能的值有:
* NotSupported
* Required
* Supports
* RequiresNew
* Mandatory
* Never
也可以对企业 bean 的所有方法指定事务属性。对 <method-name> 属性使用 *。
清单 2 显示了为容器管理的企业 bean 指定事务属性的示例。除了为 updateClaimNumber 方法分配 Mandatory 属性以外,ClaimRecord企业 bean 为所有方法都分配了 Required 属性。Coverage bean 对所有方法指派 RequiresNew 属性。
清单 2. ejb 部署描述符文件中的事务属性
<ejb-jar>
...
<assembly-descriptor>
...
<container-transaction>
<method>
<ejb-name>ClaimRecord</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>ClaimRecord</ejb-name>
<method-name>updateClaimNumber</methodname>
</method>
<trans-attribute>Mandatory</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>Coverage</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
...
</assembly-descriptor>
...
</ejb-jar>
回页首
Geronimo 配置
既然您明白了在 EJB 部署描述符中指定事务属性的通用格式,那么可以考虑一下如何在 Geronimo 中使用 OpenEJB 实现这一点。在 Geronimo 中开发 EJB 时,可以通过使用 XDoclet 生成所需的大部分单调的 EJB 编程工件 (artifact) 来节省时间。作为这些工件的一部分,XDoclet 生成了 EJB 部署描述符。
作为正常开发过程的一部分,可以在企业 bean 中指定 JavaDoc-style 标识标签。通过在企业 bean 中声明标识标签,XDoclet 可生成 ejbjar.xml。这包括属性定义的任何事务。您不用自己直接编译部署描述符 (ejb-jar.xml)。
在 XDoclet 中使用 @ejb.transaction 标识指定事务属性。在需要使用它时,可以在企业 bean 的方法之上声明它。
XDoclet 配置示例和 ejbjar.xml 生成
下面的代码片断显示了一个简洁的会话 bean 和实体 bean 示例,然后由 XDoclet 生成最终的 ejbjar.xml 文件。首先,清单 3 显示了一个名为 SampleSession 的无状态会话 bean。只需要注意与事务相关的部分即可(用粗体显示)。
清单 3. 会话 bean
package org.my.package.ejb;
/**
* Sample session bean.
* Declare all my XDoclet tags here
* ...
* ...
* @ejb.bean name="SampleSession"
* type="Stateless"
* local-jndi-name="java:comp/env/ejb/SampleSessionLocal"
* jndi-name="org.my.package.ejb/SampleSessionLocal/Home"
* view-type="both"
*
* @ejb.permission unchecked="true"
*
* @ejb.interface generate="local,remote"
* remote-class="org.my.package.ejb.SampleSession"
* local-class=" org.my.package.ejb. SampleSession Local"
* @ejb.home generate="local, remote"
* remote-class="org.my.package.ejb.SampleSession Home"
* local-class="org.my.package.SampleSession LocalHome"
* @ejb.util generate="physical"
* ...
* ...
*/
public abstract class SampleSessionBean implements javax.ejb.SessionBean {
/**
* Perform a business operation. Add something
* @param someParam the value
* @ejb.interface-method view-type="both"
* @ejb.transaction type="Required"
*/
public void doSomething(java.lang.String someParam)) {
...
}
/*
* Perform another business operation. Add something
* @param someParam the value
* @ejb.interface-method view-type="both"
* @ejb.transaction type="RequiresNew"
*/
public void doSomethingElse(java.lang.String someParam)) {
...
}
/**
* @ejb.create-method
* @ejb.transaction type="Required"
*/
public void ejbCreate ()
throws javax.ejb.CreateException
{
}
public void ejbPostCreate ()
throws javax.ejb.CreateException
{
}
protected javax.ejb.SessionContext _ctx = null;
public void setSessionContext( javax.ejb.SessionContext ctx )
{
_ctx = ctx;
}
protected javax.ejb.SessionContext getSessionContext()
{
return _ctx;
}
}
同样的标识 @ejb.transaction 被用来指定该实体 bean 的事务属性。清单 4 显示如何指定实体 bean 的事务属性。同样,只需要注意粗体的标识即可。
清单 4. 实体 bean
package org.my.package.ejb;
/**
*
* @ejb.bean
* type="CMP"
* cmp-version="2.x"
* name="ClaimEntry"
* local-jndi-name="org.my.package.ejb/ClaimLocalHome"
* view-type="local"
* primkey-field="name"
*
*
* @xx-ejb.data-object
* container="true"
* setdata="true"
* generate="true"
*
* @ejb.value-object
*
* @ejb.transaction type="Required"
* @ejb.permission unchecked="true"
* @struts.form include-all="true"
*
* @web.ejb-local-ref
* name="ejb/ClaimLocal"
* type="Entity"
* home="org.my.package.ejb.ClaimLocalHome"
* local="org.my.package.ejb.ClaimLocal"
* link="PhoneBookEntry"
*
* @ejb.persistence table-name="Claim"
*
*/
public abstract class ClaimBean
implements javax.ejb.EntityBean
{
* ... EJB entity bean implementation here
}
在编译过程中执行 XDoclet 时,生成了 ejb-jar.xml。清单5 显示了文件的事务相关部分。注意粗体显示的 <transaction-type> 和 <trans-attribute> 元素。
清单 5. 生成的 ejb-jar.xml 片断
...
<ejb-jar >
<description><![CDATA[No Description.]]></description>
<display-name>Generated by XDoclet</display-name>
<enterprise-beans>
<!-- Session Beans -->
<session >
<description><![CDATA[Sample session
bean.]]></description>
<ejb-name>SampleSession</ejb-name>
<home>org.my.package.ejb.SampleSessionHome</home>
<remote>org.my.package.ejb.SampleSession</remote>
<local-home>org.my.package.ejb.SampleSessionLocalHome
</local-home>
<local>org.my.package.ejb.SampleSessionLocal</local>
<ejb-class>org.my.package.ejb.SampleSessionSessionSession
</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
...
<!-- Entity Beans -->
<entity >
<description><![CDATA[]]></description>
<ejb-name>Claim</ejb-name>
<local-home>
org.my.package.ejb.ClaimLocalHome</local-home>
<local>org.my.package.ejb.ClaimLocal</local>
<ejb-class>org.my.package.ejb.ClaimCMP</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>Claim</abstract-schema-name>
...
</entity>
...
<container-transaction >
<method >
<ejb-name>Claim</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Local</method-intf>
<method-name>doSomething</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Remote</method-intf>
<method-name>doSomething</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Local</method-intf>
<method-name>doSomethingElse</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction >
<method >
<ejb-name>SampleSession</ejb-name>
<method-intf>Remote</method-intf>
<method-name>doSomethingElse</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
...
</ejb-jar>
事务同步
容器管理的事务允许 EJB 容器指定事务边界,这可以简化您的工作。然而,当事务中止时,可能需要执行一些 bean 状态的恢复工作。对于无状态会话 bean,可能抛出一个简单的异常。有状态会话 bean 表示了对话状态(或商业流程),这可能会跨越几个 bean 方法调用。
如果要求有状态会话 bean 获得事务边界状态事件通知,则需要编写企业 bean 代码来实现可选的 javax.ejb.SessionSynchronization 接口。您必须实现定义在接口上的下列方法:
* afterBegin() —— 在新事务启动之后但在调用业务方法之前通知会话 bean。在事务提交之前,bean 实例可以做任何它所需要的数据库读取操作。在缓冲事务所需要的数据时,这很有用。
* beforeCompletion() —— 在业务方法完成之后但是在事务提交之前通知会话 bean。如果有任何缓冲数据,可以将其更新到数据库中。bean 还可以在会话上下文中通过调用 setRollBackOnly() 执行事务的手动回滚。
* afterCompletion(boolean committed) —— 在事务提交之后通知会话 bean。提交的布尔值指出是提交事务还是中止事务。如果该值为 true,则事务成功获得提交。如果该值为 false,则事务中止。因此,bean 的对话状态/实例变量可以被恢复或重新设置。
避免使用的方法
既然 EJB 容器是负责控制事务边界,那么您不应该调用任何可能干涉容器边界划分的方法。如果您正在实现容器管理的事务,请确保企业 bean 方法不会调用下列方法:
* java.sql.Connection 的 commit、setAutoCommit 和 rollback 方法
* javax.ejb.EJBContext 的 getUserTransaction 方法
* javax.transaction.UserTransaction 的任何方法
回滚
在某些情况下您可能需要明确中止事务。有两种回滚容器管理的事务的方式:
* 让容器自动回滚事务。如果有任何企业 bean 抛出的运行时异常,就会发生这种回滚。
* 调用 EJBContext 接口的 setRollBackOnly() 方法。在发生回滚时,允许您进行控制。或许由于一些有效性验证失败或存在数据完整性问题,您可能需要回滚整个事务并抛出一个应用程序异常。应用程序异常不会自动导致容器回滚一个异常。
回页首
结束语
在本系列的第 1 部分,简单介绍了事务和 EJB 事务的两个选择。您可以看到容器管理的事务如何使您专注于您的企业 bean 的业务逻辑,而将事务逻辑和管理的复杂性留给 EJB 容器。
使用容器管理的事务,您只需要关心企业 bean 如何参与到事务中,并通过 EJB 部署描述符的简单配置来实现这一点。Geronimo 应用服务器、OpenEJB 和 XDoclet 将帮助您简化如何指定容器管理的设置,并将您从繁重的 EJB 工件编码工作中解放出来。
继续关注本系列的第 2 部分,您将了解 bean 管理的事务,在第 3 部分中,我们会将二者综合使用。
参考资料
学习
* 阅读 “利用 Geronimo 深入 EJB Web 应用程序”(developerWorks,2005 年 7 月),了解如何在 Geronimo 中使用 EJB。
* 通过 “在 Apache Geronimo 上部署 J2EE 应用程序”(developerWorks,2006 年 1 月)了解如何部署 JavaServer Pages (JSP)、servlet 和 Apache Geronimo 上的不同 EJB。
* 查看 Dale Green 的文章 “Enterprise Beans”,获得关于 Geronimo 中部署描述符的更多信息。
* 阅读更多有关 Sun 公司的 EJB 规范 的信息。
* 学习有关 XDoclet 的更多信息。
* 阅读 Nicholas Chase 与 David Blevins(OpenEJB 的共同创始人)的访谈 “Geronimo 叛逆者:OpenEJB 和 Apache Geronimo 的 EJB 实现”(developerWorks,2006 年 5 月),了解 OpenEJB 是如何被选为 Geronimo 的 EJB 实现的。
* 加入 Apache Geronimo 网站的 邮件列表。
* 阅读 “构建更佳的 J2EE 服务器,开源之路”(developerWorks,2005 年 5 月),获得有关 Geronimo 背后的开发过程的重要信息,包括其 JSR-88 支持。
* 查看 developerWorks Apache Geronimo 项目专区,获得有助于您现在使用 Geronimo 开始开发的文章、教程和其他参考资料。
* 在 developerWorks 的 现在开始学习 Apache Geronimo 部分查找对于初学者和有经验的用户有用的参考资料。
* 查看提供的 IBM Support for Apache Geronimo,它会使您在开发 Geionimo 应用程序时得到世界级的 IBM 支持。
* 访问 developerWorks 开放源码专区,从那里可以获得大量的 how-to 信息、工具和项目更新,这些有助于您使用开放源码技术进行开发,并将这些技术 IBM 产品结合使用。
* 在 “developerWorks 开放源码专区” 上浏览所有可获得的 Apache 文章 和 免费 Apache 教程。
* 浏览 Safari bookstore 上的有关书籍和其他技术主题。
获得产品和技术
* 下载 Apache Geronimo, Version 1.0。
* 使用 IBM 试用软件 改进您的下一个开放源码开发项目,可以通过下载或从 DVD 中获得这些软件。
* 下载 IBM WebSphere® Application Server Community Edition V1.0 的免费副本 —— 它是一个轻量级的 J2EE 应用服务器,使用 Apache Geronimo 开放源码技术构建而成,用于帮助您加速开发和部署工作。
讨论
* 参与论坛讨论。
* 与 Apache Geronimo blog 上的 Geronimo 开发保持同步。
* 通过参与 developerWorks blogs 加入 developerWorks 社区。
关于作者
Jonathan Sagorin 是一位自由开发人员。在 10 年职业生涯里,他大部分时间都是一名顾问,为用户提供自定义 Java 解决方案。业余时间他尝试玩垒球和即兴表演(不必同时进行,虽然他的垒球队友不这么认为)。
相关推荐
Apache Geronimo是一款开源的应用服务器,由Apache软件基金会开发,旨在提供一个用于部署和管理Java企业应用的平台。Geronimo 3.0是该软件的一个重要版本,它集成了许多改进和新特性,旨在提高性能、可扩展性和易用...
Apache Geronimo是一款开源的应用服务器,它遵循Java EE规范,提供了部署Web应用程序的框架。`geronimo-web.xml`是Geronimo针对Web应用的特定部署计划文件,它与标准的`web.xml`文件一起使用,用于在Geronimo服务器...
### Apache Geronimo 中部署 Web 服务的知识点详解 #### 一、Apache Geronimo简介与Web服务支持 Apache Geronimo 是一个基于 J2EE 1.4 标准的强大开源应用服务器,由 Apache Software Foundation 发起。Geronimo ...
- **EJB容器**:用于运行Enterprise JavaBeans,提供事务、安全性、生命周期管理和资源注入等功能。 - **JMS服务器**:支持Java消息服务,用于异步通信和解耦应用组件。 - **JDBC驱动和数据源**:提供与数据库的连接...
总的来说,Apache Geronimo的事务管理组件是其Java EE能力的重要组成部分,通过提供可靠的事务服务,它帮助开发者构建出高可用、高性能的企业级应用程序。解压并研究"txmanager.zip"的内容,将有助于深入理解...
Apache Geronimo是一款开源的应用服务器,它由Apache软件基金会开发并维护,主要支持Java和Java Enterprise Edition (JavaEE) 应用程序。这个压缩包"Apache Geronimo Config.zip"很可能包含了与配置Apache Geronimo...
Servlet容器是Java EE应用服务器的核心组成部分,Geronimo就提供了这样的容器。 2. **JSP(JavaServer Pages)**:提供了一种简便的方式来创建动态网页,将HTML与Java代码结合在一起。JSP引擎负责将JSP文件转换成...
Java SE和EE的配置 地位 MicroProfile Config规范的实现。 基本原理 许多项目工件(例如WAR,EAR)仅应创建一次,然后在不同的客户,阶段等安装,它们需要针对那些... Romain Manni-Bucau(Apache / Tomitribe),Ro
1. **Geronimo应用服务器**:Apache Geronimo 是一个开源的应用服务器,它实现了Java EE(现称为Jakarta EE)规范,提供了包括EJB、JMS、JPA、Servlet和JSP等在内的多种服务。Geronimo Devtools是针对这个服务器的...
6. **许可证文件**:Apache Geronimo和Microprofile都是遵循开源许可证的项目,因此压缩包中应包含相关的许可证信息,表明代码可以被自由使用、修改和分发的条款。 7. **README**:一个简短的说明文件,通常会提供...
Apache Geronimo是一款开源的应用服务器,它遵循Java EE(Java Platform, Enterprise Edition)规范,为开发者提供了一个构建、部署和管理企业级应用的平台。"Mirror of Apache Geronimo javamail.zip" 提供的是...
Apache Geronimo是一款开源的应用服务器,它遵循Java Enterprise Edition (Java EE) 规范,提供了一个轻量级、模块化的平台来部署和管理企业级应用。MicroProfile是Java社区为微服务开发创建的一个开放框架,它旨在...
Chapter 1: Getting Started with Geronimo 7 Motivation behind the Geronimo project 7 Constituent projects 8 Apache Geronimo architecture 11 Downloading and running Apache Geronimo 12 Geronimo ...
标签:apache、geronimo、specs、jcache、spec、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和...
geronimo-javamail_1.4_spec-1.7.1.jar
Apache Geronimo是一款开源的J2EE应用服务器,它实现了多种J2EE规范,包括Java Servlet、JSP、EJB、JMS、JTA等。Geronimo由Apache软件基金会维护,提供了稳定、安全且可扩展的平台,用于运行和管理企业级应用程序。...
标签:annotation_1、specs、apache、0_spec、geronimo、jar包、java、API文档、中文版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持...
对应Maven信息:groupId:org.apache.geronimo.specs,artifactId:geronimo-j2ee-management_1.1_spec,version:1.0.1 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性...
标签:specs、jta_1、apache、1_spec、geronimo、jar包、java、API文档、中文版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,...