WebLogic中文博客(镜像)
WebLogic及中间件监控技术研究

计时器和工作管理器 API (CommonJ) 编程人员指南
 

本文整理自 WebLogic 10.0中文文档。

更多CommonJ规范的信息参考:http://www.ibm.com/developerworks/library/specification/j-commonj-sdowmt/index.html

计时器和工作管理器 API

此文档概述计时器和工作管理器 API,并说明其在应用程序中的实现方法。

   

计时器和工作管理器 API 的描述

计时器和工作管理器 API 是按照 BEA Systems IBM 共同创建的规范进行定义的。通过此 API,可以并发编写在 Java EE 应用程序中的 EJB Servlet 程序。此 API 经常被称为 CommonJ

CommonJ API 包含下列组件:

虽然 commonj.timer commonj.work 属于同一个 API 的一部分,但它们的功能却各不相同。您可以根据应用程序的特定需要实现其中的一种。CommonJ 计时器 API 适用于按特定间隔调度工作的情形;例如,您知道某一项作业应在特定时间运行的情形。而 CommonJ 工作 API 适用于根据优先级处理工作的情形。例如,您不能准确预测一项特定作业的发生时间,而是希望这项作业被赋予更高或更低的优先级。

下列部分将详细描述 CommonJ API

   

计时器 API 概述

计时器 API 包含以下三个接口:

计时器管理器提供在受管环境中创建和使用计时器的框架。计时器监听器接收计时器通知。TimerManager.schedule() 方法用于调度 TimerListener,使其在特定时间或间隔运行。

有关如何实现计时器的详细描述,请参阅使用计时器 API

TimerManager 接口

TimerManager 接口在应用程序中提供常规调度框架。受管的环境可以支持多个 TimerManager 实例。这就是说,一个应用程序可以包含多个 TimerManager 实例。

创建和配置计时器管理器

可通过部署描述符在部署期间配置 TimerManagerTimerManager 定义还可以包含其他实现特定的配置信息。

一旦在部署描述符中定义了 TimerManager,您就可以在本地 Java 环境中使用 JNDI 查找访问它的实例。每次调用 JNDI lookup() 访问 TimerManager 时,都将返回 TimerManager 的一个新逻辑实例。

TimerManager 接口是线程安全的。

有关使用 JNDI 的详细信息,请参阅"WebLogic JNDI 编程"

挂起 TimerManager

可使用 suspend() resume() 方法,挂起和恢复 TimerManager。当挂起 TimerManager 时,所有待定的计时器将延迟到 TimerManager 恢复时为止。

停止 TimerManager

可使用 stop() 方法停止 TimerManager。在调用 stop() 方法后,所有活动的计时器都将停止,而且 TimerManager 实例将停止监视所有 TimerListener 实例。

TimerListener 接口

使用 commonj.timers 包的所有应用程序都需要实现 TimerListener 接口。

Timer 接口

当通过 TimerManager 调度计时器时,将返回 Timer 接口的实例。

   

使用计时器 API

此部分将简述在应用程序中使用计时器 API 时的必需步骤。

在部署应用程序前,确保已创建了包含计时器管理器资源引用的部署描述符。

这样可以通过 JNDI 访问 TimerManager。有关 JNDI 查找的详细信息,请参阅"WebLogic JNDI 编程"

下面描述计时器 API 的实现过程:

  1. IntialContext inctxt = new InitialContext();

    有关 JNDI 查找的详细信息,请参阅"WebLogic JNDI 编程"

  2. TimerManager mgr = (TimerManager)ctx.lookup(`java:comp/env/timer/MyTimer');

    在此语句中,将 JNDI 查找结果强制转换成 TimerManager

  3. TimerListener listener = new StockQuoteTimerListener(`abc', `example');

  4. mgr.schedule(listener, 0, 1000*60)

    schedule() 方法返回计时器对象。

  5. public void timerExpired(Timer timer) {
         //此方法执行
         //
    业务逻辑

    }

计时器管理器示例

package examples.servlets;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import commonj.timers.*;

/**
* TimerServlet 演示了 commonj 计时器的简单使用
*/
public class TimerServlet extends HttpServlet {

/**
  *
非常简单地实现服务方法
  *
该实现安排了 commonj 计时器。
  */
  public void service(HttpServletRequest req, HttpServletResponse res)
    throws IOException
  {
    res.setContentType("text/html");
    PrintWriter out = res.getWriter();
    try {
      InitialContext ic = new InitialContext();
      TimerManager tm = (TimerManager)ic.lookup
        ("java:comp/env/tm/default");
      //
立即开始每 10 秒执行一次计时器
      tm.schedule (new MyTimerListener(), 0, 10*1000);
      out.println("<h4>Timer scheduled!</h4>");
    } catch (NamingException ne) {
      ne.printStackTrace();
      out.println("<h4>Timer schedule failed!</h4>");
    }
  }

  private static class MyTimerListener implements TimerListener {
    public void timerExpired(Timer timer) {
      System.out.println("timer expired called on " + timer);
      //
此处一些有用的工作...
      //
只取消计时器
      System.out.println("cancelling timer ...");
      timer.cancel();
    }
  }
}

   

使用作业调度程序

此部分描述作业调度程序功能的用法。通过作业调度程序,您可以在群集环境中实现 commonj.timer API

作业调度程序实际上就是可以在群集中使用的 commonj.timer API 包的实现。在此上下文,作业被定义为要提交给作业调度程序进行执行的 commonj.timers.TimerListener 实例。

本部分包含下列主题:

计时器的生命周期

在应用程序中实现 commonj.timer API 时,可以为计时器配置两种可能的生命周期。

每一计时器有其自己的优缺点。本地计时器能以短得多的作业处理时间间隔处理作业。由于群集有持久性要求,因此作业调度程序不能如此精确地处理作业。另一方面,作业调度程序更适合于在即使创建任务的初始服务器出现故障的情况下也必须执行的任务。

实现和配置作业调度程序

此部分将简述在应用程序中实现作业调度程序的基本过程以及配置 WebLogic Server 环境以利用作业调度程序的基本过程。

数据库配置

为了维持持久性,并使计时器支持群集,作业调度程序需要数据库连接。作业调度程序功能与服务器迁移支持相同的数据库供应商和版本。

为方便起见,可与会话持久性、服务器迁移等使用相同的数据库。

在数据库中,必须基于以下模式创建一个称为 WEBLOGIC_TIMERS 的表:

CREATE TABLE WEBLOGIC_TIMERS (
  TIMER_ID VARCHAR2(100) NOT NULL,
  LISTENER BLOB NOT NULL,
  START_TIME NUMBER NOT NULL,
  INTERVAL NUMBER NOT NULL,
  TIMER_MANAGER_NAME VARCHAR2(100) NOT NULL,
  DOMAIN_NAME VARCHAR2(100) NOT NULL,
  CLUSTER_NAME VARCHAR2(100) NOT NULL,
  CONSTRAINT SYS_C00323062 PRIMARY KEY(TIMER_ID, CLUSTER_NAME, DOMAIN_NAME)
)

数据源配置

在创建了采用所需模式的表之后,必须定义一个可在群集配置内引用的数据源。只有为 Cluster MBean DataSourceForJobScheduler 特性定义了有效数据源后,才能使用作业调度程序功能。您可以在 WebLogic Server 管理控制台对此进行配置。

以下的代码摘自 config.xml,用于说明对此进行定义的方法:

<domain>
...
 <cluster>
  <name>Cluster-0</name>
  <multicast-address>239.192.0.0</multicast-address>
  <multicast-port>7466</multicast-port>
  <data-source-for-job-scheduler>JDBC Data     Source-0</data-source-for-job-scheduler>
 </cluster>
...
 <jdbc-system-resource>
  <name>JDBC Data Source-0</name>
  <target>myserver,server-0</target>
  <descriptor-file-name>jdbc/JDBC_Data_Source-0-3407-jdbc.xml</descriptor-    file-name>
 </jdbc-system-resource>
</domain>

作业调度程序中的 JNDI 访问

与常规 commonj.timer API 相比,在群集计时器中执行 JNDI 查找的过程有所不同。下面的代码段说明如何将 JNDI 查找强制转换成 TimerManager

InitialContext ic = new InitialContext();
commonj.timers.TimerManager jobScheduler =(common.timers.TimerManager)ic.lookup
   ("weblogic.JobScheduler");
commonj.timers.TimerListener timerListener = new MySerializableTimerListener();
jobScheduler.schedule(timerListener, 0, 30*1000);
// 30 秒执行一次此作业

不支持的方法和接口

作业调度程序环境并非支持 commonj.timer API 的所有方法和接口。不支持下列方法和接口:

   

工作管理器 API 的描述

工作管理器 (commonj.work) API 提供的接口允许应用程序在一个容器中并发地执行多个工作项。

实际上,此 API 就是 java.lang.Thread API 的容器管理替代方法。java.lang.Thread API 不适用于受管 Java EE 环境中承载的应用程序。在这样的环境中,工作管理器 API 替代方法的效果更好,因为它允许容器全面查看和控制所有执行线程。

注意:

工作管理器 API 不提供故障转移和持久性机制。如果受管服务器环境出现故障或关闭,则当前所有工作都将丢失。

工作管理器接口

此部分概述工作管理器 API 中定义的接口。有关使用这些接口的详细信息,请参阅 commonj.work package  javadoc

工作管理器 API 包含下列接口:

注意:

WorkListener 实例总与通过 WorkManager 调度 Work 的初始线程在同一个 JVM 中执行。

工作管理器部署

在适当部署描述符中通过 resource-ref 在服务器级别定义工作管理器。在其他描述符中可以是 web.xml ejb-jar.xml

下面的部署描述符片段说明如何配置 WorkManager



<resource-ref>
   <res-ref-name>wm/MyWorkManager</res-ref-name>
   <res-type>commonj.work.WorkManager</res-type>
   <res-auth>Container</res-auth>
   <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
...

注意:

建议您为 WorkManager 对象的 JNDI 名称空间使用前缀 java:comp/env/wm

   

工作管理器示例

此部分的工作代码示例在 HTTP Servlet 中使用 CommonJ 工作管理器。

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import weblogic.work.ExecuteThread;
import commonj.work.WorkManager;
import commonj.work.Work;
import commonj.work.WorkException;

public class HelloWorldServlet extends HttpServlet {

   public void service(HttpServletRequest req, HttpServletResponse res)
      throws IOException
   {
      res.setContentType("text/html");
      PrintWriter out = res.getWriter();


      try {
         InitialContext ic = new InitialContext();
         System.out.println("## [servlet] executing in: " +
            ((ExecuteThread)Thread.currentThread()).getWorkManager()
            .getName());
         WorkManager wm = (WorkManager)ic.lookup
            ("java:comp/env/foo-servlet");
         System.out.println("## got Java EE work manager !!!!");
         wm.schedule(new Work(){
         public void run() {
         ExecuteThread th = (ExecuteThread) Thread.currentThread();
         System.out.println("## [servlet] self-tuning workmanager: " +
           th.getWorkManager().getName());
         }
         public void release() {}

         public boolean isDaemon() {return false;}
         });
}
catch (NamingException ne) {
         ne.printStackTrace();}

catch (WorkException e) {
         e.printStackTrace();
}

out.println("<h4>Hello World!</h4>");
// 不要关闭输出流 - 而是启用 servlet 引擎关闭输出流
//
以实现更佳性能。
System.out.println("finished execution");}

}

 


只有注册用户登录后才能发表评论。


网站导航: