使用企业 Bean 的 EJB 计时器服务创建计时器

您可以使用企业 Bean 来利用 EJB 计时器服务,从而调度基于时间的事件。

关于此任务

为了支持 EJB 3.1 规范,您可以创建非持久性 EJB 计时器。本产品还支持扩展的 TimerService API 以用于创建编程计时器。此外,您可以配置 EJB 容器以在应用程序启动时自动创建计时器。

WebSphere® Application Server 实现 Enterprise JavaBeans(EJB) 计时器服务。 根据您的业务需要,可以使用持久性计时器或非持久性计时器。 如果正在为基于时间的事件创建计时器,该事件要求确保计时器在超出服务器的生命周期后仍然存在,那么持久性计时器非常有用。 先前启动的持久性计时器在服务器启动时会自动启动,并且在服务器关闭并重新启动过程中持久存在。例如,您可以使用持久性计时器来启动系统应用程序或发送有关计时器到期的状态通知。非持久性计时器在以下非关键情况下非常有用:跳过或重新执行计时器操作而不会产生负面的业务影响,如轮询温度。

可以以编程方式创建计时器。 也可以通过使用 Bean 类中的 @Schedule 注释或使用 ejb-jar.xml 部署描述符中的 timer 元素来自动创建计时器。通过自动创建计时器,您无需依赖企业 Bean 调用以编程方式启动 EJB 计时器服务创建方法即可调度计时器。

持久性计时器

持久性计时器是作为调度程序服务任务来实现的。缺省情况下,内部或预先配置的调度程序实例会用于管理这些任务,并且它们会在与服务器进程相关联的 Apache Derby 数据库中持续存在。

您可以对内部调度程序实例执行基本的定制。有关定制调度程序实例的信息,请参阅配置计时器服务信息。

计时器的创建和取消具有事务性和持久性。如果计时器是在稍后进行回滚的事务中创建的,那么创建的计时器也会回滚。类似的规则适用于取消计时器的操作。先前启动的计时器在应用程序服务器关闭并重新启动后持续存在。

非持久性计时器

EJB 3.1 扩充了 EJB 计时器服务,以便除了启用持久性计时器之外还启用非持久性 EJB 计时器。非持久性计时器的许多语义和行为与持久性计时器的相同,但是没有数据存储器的开销。 非持久性计时器的生命周期与持久性计时器的不同。持久性计时器在应用程序服务器关闭并重新启动后持续存在,但非持久性计时器只在应用程序服务器处于活动状态时才处于活动状态。与持久性计时器不同的是,没有命令来查找或取消非持久计时器。应用程序服务器停止或未能保持活动状态时,非持久性计时器会被取消。

与持久性计时器一样,非持久性计时器的创建和取消是事务性的。如果计时器是在稍后进行回滚的事务中创建的,那么创建的计时器也会回滚。类似的规则适用于取消计时器的操作。

您可以配置非持久计时器以与持久计时器共享线程池,或具有一个不与持久计时器共享的唯一线程池。

以编程方式创建的计时器

以编程方式创建的持久性计时器将在应用程序服务器关闭和重新启动期间维护,除非被取消。应用程序代码或系统管理员负责删除不再需要的以编程方式创建的计时器。

要以编程方式创建与企业 Bean 相关联的计时器,Bean 应该对适用的上下文实例调用 getTimerService() 方法以获取对 TimerService 对象的引用。 Bean 还会调用其中一个 TimerService 方法(如 createTimer)以指定该 Bean 的计时器。此 Timer 实例现在已与您的 Bean 相关联。在 EJB 3.1 规范中对 TimerService 方法进行了描述。现在,您可以将 Timer 实例作为本地对象传递至其他 Java™ 代码。Java 代码获取计时器实例后,该代码可以使用由 javax.ejb.Timer 接口定义的任何方法(如 cancel() 或 getTimeRemaining() 方法)。

在集群环境中,以编程方式创建的持久性计时器可以在任何集群成员中运行,但是以编程方式创建的非持久性计时器只能在创建它的 JVM 中运行。

自动创建的计时器
EJB 3.1 规范扩充了 EJB 计时器服务,以在应用程序不依赖于 Bean 调用启动时使计时器的自动创建能够以编程方式启动其中一个计时器服务创建方法。使用 @Schedule 注释或 timeout-method 部署描述符元素来自动创建计时器。自动创建的计时器由容器创建为应用程序部署的结果。
避免故障 避免故障: CancelEJBTimers 命令还将取消自动创建的计时器。取消自动创建的计时器后,重新创建这些计时器的唯一方法是卸载应用程序并将其重新安装。gotcha
集群环境中的计时器

在集群环境中,持久计时器仅在一个集群成员中运行,该集群成员不一定是在其中创建持久性计时器的集群成员。非持久性计时器在创建该持久性计时器的每个集群成员中运行,自动非持久性计时器在包含 EJB 的每个集群成员中运行。

自动持久性计时器的包含模块或应用程序卸载后,会将其从其持久存储器中移除。因此,请勿使用“推出更新”功能来更新使用自动持久性计时器的应用程序。这样做将会卸载并重新安装应用程序,而集群仍在运行,这在以下情况下可能会导致故障:

  • 如果在其他集群成员中运行的计时器在数据库条目移除之后且在数据库条目重新创建之前激活,那么计时器将失败。在此情况下,会将 com.ibm.websphere.scheduler.TaskPending 异常写入到首次故障数据捕获 (FFDC) 以及 SCHD0057W 消息,表明数据库中的任务信息已更改或者已取消。
  • 如果在数据库中的计时器数据已更新之后,计时器在尚未更新的集群成员上激活,那么在新计时器信息与仍在集群成员中运行的旧应用程序代码不兼容的情况下,计时器可能会失败或者导致其他故障。

在产品中使用代理服务器时,如果调度程序配置为用于 EJB 计时器服务的调度程序,请勿在单元级别定义调度程序。这样做会阻止持久性计时器运行。如果代理服务器获取了调度程序租赁,那么会发生此情况。由于没有任何应用程序在代理服务器中运行,因此没有应用程序代码来处理调度程序所发送的计时器事件。

重试和错过的超时

如果您使用 EJB 计时器,那么您必须了解故障、重试和错过超时的概念。

  • 故障是指已尝试但未成功的超时执行。
  • 重试是指为了成功执行先前已尝试但失败的超时的其他尝试。
  • 错过的执行是指必须已尝试但未尝试(由于服务器不可用或者忙于重试先前失败的超时)的超时。
重试行为反映:
  • 服务器重试失败超时的额外次数
  • 这些服务器重试的时间间隔
错过的超时行为反映出:
  • 服务器是否最终尝试了错过的超时
  • 当发生这些尝试时,是否最终尝试了错过的超时
  • 错过超时尝试之间的时间间隔
表 1. 重试和错过的超时行为. 持久性和非持久性计时器的重试和错过超时行为。
特性 缺省行为 可配置
重试次数 成功时进行的次数。

如果在服务器中达到了持久性计时器的调度程序失败阈值,那么将临时取消激活持久性计时器。有关更多信息,请参阅有关停止失败任务的主题。

对于非持久性计时器,可配置
重试的时间间隔 首个重试是即时的。

持久性计时器在配置的调度程序轮询时间间隔进行后续重试,非持久性计时器在配置的重试时间间隔进行后续重试。

错过的超时恢复 恢复所有错过的超时。
当恢复错过的超时时 在阻止重试停止时,持久性和非持久性计时器恢复错过的超时。此外,当不可用服务器重新启动时,持久性计时器恢复超时。
下次超时,在重试已成功且恢复了错过的超时之后 在下一个原始调度的时间。

可配置特征是在持久性计时器的调度程序实例和非持久性计时器的非持久性计时器配置上配置。

以下方案说明重试和错过的超时行为如何影响持久性和非持久性计时器的超时。

持久性计时器方案:

将创建一个持久性计时器并且配置为在上午 10:00 首次运行,此后每隔一小时运行一次。 支持计时器的调度程序以 30 秒轮询时间间隔来配置。

计时器在上午 10:00 运行但是失败,因为数据库不可用。计时器会立即重试,并且在轮询调度程序时每隔 30 秒进行重试,并且一直失败,直至下午 12:30。此时,重试将成功,因为数据库现在重新联机,并且服务器因此停止重试先前失败的尝试。

现在,服务器通过错过的超时来开始工作。首先,服务器尝试必须已在上午 11:00 运行的超时,这将在下午 12:31 成功。当 30 秒之后再次轮询调度程序时,将尝试必须已在下午 12:00 运行的超时,这将在下午 12:32 成功。服务器现在是最新的,并且下一次超时发生在其最初调度的时间,即下午 1:00,相对于上一次成功的一小时之后(这可能是下午 1:32)。将来,将会维护原始调度。 调度不是根据上一次成功超时的时间来更新。

非持久性计时器方案:

将创建一个非持久性计时器并且配置为在上午 10:00 首次运行,此后每隔一小时运行一次。 此非持久性计时器配置为具有重试计数 5,且重试时间间隔为 30 分钟。

计时器在上午 10:00 运行但是失败,因为数据库不可用。将立即重试计时器,并且再次失败。现在,由于已执行了初始即时重试,因此服务器在下一个重试之前等待已配置的重试时间间隔 30 分钟。重试将在上午 10:30 和上午 11:00 进行,并且均失败。最后,第四次重试在上午 11:30 进行并且成功,因为数据库现在重新联机。

现在,服务器通过错过的超时来开始工作。原定于上午 11:00 的超时是立即运行,并在上午 11:31 点成功。服务器现在是最新的,并且下一次超时发生在其最初调度的时间,即下午 12:00,相对于上一次成功的一小时之后(这可能是下午 12:32)。

getNextTimeout 和 getTimeRemaining 方法的行为

对于持久性和非持久性计时器,Timer.getNextTimeout 方法返回一个 java.util.Date 对象,此对象指示安排计时器下次执行的时间。从超时回调方法中为基于时间间隔或日历的计时器调用 getNextTimeout 方法时,此方法将返回下一个调度的时间;对于无将来超时的基于日历的计时器,此方法根据 EJB 3.1 规范的要求而抛出 NoMoreTimeoutsException 异常。从超时回调方法为单一操作计时器调用 getNextTimeout 方法时,此方法将返回原始调度的时间。如果超时回调方法失败并且正在进行重试,那么 getNextTimeout 方法将继续返回原始调度的时间,如同失败的异常从未发生。在所有情况下,Timer.getTimeRemaining 方法返回 getNextTimeout 返回值与当前系统时间之间的毫秒差值,如果调度的异常时间是在过去,那么这可能导致一个负数。

自动创建的计时器的继承行为

bean 类的层次结构中的自动计时器方法将导致创建多个计时器。与计时器方法相关联的计时器数量不是由源代码中方法的出现数量决定。相反,与计时器方法相关联的计时器数量是由该方法可见的 bean 数量决定。例如:

@Stateless
public class Abean {

   @Schedule(hour=”1”)
   public void timerMethod1()


@Stateless
public class Bbean extends Abean {

   @Schedule(hour=”2”)
   public void timerMethod2()


@Stateless
public class Cbean extends Bbean {

   @Schedule(hour=”2”)
   public void timerMethod2()

在上述 bean 类层次结构中,将创建三个具有回调方法 Abean.timerMethod1 的自动计时器,每个自动计时器对应于每个 bean 实例(对该方法可视)。将创建一个具有回调方法 Bbean.timerMethod2 的计时器,并且由于该方法是由 bean Cbean 覆盖,那么将仅创建一个具有回调方法 Cbean.timerMethod2 的计时器。

在先前示例中,当容器处理 bean Abean 时,将创建单个自动计时器(具有回调方法 Abean.timerMethod1)。

当容器处理 bean Bbean 时,将创建一个具有回调方法 Bbean.timerMethod2 的自动计时器,并将创建另一个具有回调方法 Abean.timerMethod1 的自动计时器。

当容器处理 bean Cbean 时,将创建一个具有回调方法 CBean.timerMethod2 的自动计时器。创建另一个具有回调方法 Abean.timerMethod1 的自动计时器。 处理 bean Cbean 时,不会创建 Bbean.timerMethod2 的计时器。Bbean.timerMethod2 在 Cbean 的类层次结构中不可见,因为它将由方法 Cbean.timerMethod2 覆盖。

请考虑另一个与先前示例类似的示例,如果 @Stateless 注释已从类 Abean 和 Bbean 中移除,那么该类 Cbean 是唯一 EJB。在此情况下,创建的自动计时器仅对 Cbean 可见;一个是具有回调方法 Abean.timerMethod1 的自动计时器,一个是具有回调方法 Cbean.timerMethod2 的自动计时器。

虽然 bean 可以在继承的 bean 回调方法中共享相同代码,但是运行时行为可能是多态的。例如:

public class Employee {

   @Schedule(hour=”1”, dayOfMonth=”-1”, info = "payroll timer")
   public void getSalaryIncrease() {
      printChecks(salary * rate());
   }

   protected float rate() {
      return (float)1.01;
   }

}

public class Manager extends Employee {

   protected float rate() {
      return (float)1.15;
   }

}

public class Executive extends Manager {

   protected float rate() {
      return (float)1.30;
   }

}

在先前示例中,每个 bean 实例具有一个包含回调方法 getSalaryIncrease() 的自动计时器。 尽管相同回调代码是由每个计时器共享,但是请注意,由于多态性,每个 bean 用于计算工资增长的速率不同。也就是说,计时器回调方法可能具有多态性,与任何 Java 方法的方式相同。

过程

结果

已经以编程方式或自动配置持久性或非持久性的 EJB 计时器。


指示主题类型的图标 任务主题



时间戳记图标 最近一次更新时间: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tejb_timerserviceejb_enh
文件名:tejb_timerserviceejb_enh.html