計時器和工作管理器 API (CommonJ) 編程人員指南
本文整理自 WebLogic 10.0中文文檔。
更多CommonJ規(guī)范的信息參考:http://www.ibm.com/developerworks/library/specification/j-commonj-sdowmt/index.html
計時器和工作管理器 API
此文檔概述計時器和工作管理器 API,并說明其在應(yīng)用程序中的實現(xiàn)方法。
?
?
計時器和工作管理器 API 的描述
計時器和工作管理器 API 是按照 BEA Systems 和 IBM 共同創(chuàng)建的規(guī)范進行定義的。通過此 API,可以并發(fā)編寫在 Java EE 應(yīng)用程序中的 EJB 和 Servlet 程序。此 API 經(jīng)常被稱為 CommonJ。
CommonJ API 包含下列組件:
通過計時器 API,應(yīng)用程序可以為在某一應(yīng)用程序中定義的特定監(jiān)聽器調(diào)度和接收計時器通知回調(diào)。通過計時器,您可以在特定時間或間隔調(diào)度和執(zhí)行工作。請參閱計時器 API 概述。
此 API 通過導入 commonj.timer 包來實現(xiàn)。
通過工作管理器 API,應(yīng)用程序可以確定 EJB 或 Servlet 中工作的優(yōu)先級。應(yīng)用程序可采用編程方式,在一個容器中執(zhí)行多個工作項。請參閱工作管理器 API 的描述。
此 API 通過導入 commonj.work 包來實現(xiàn)。
除 CommonJ 工作管理器 API 外,WebLogic Server 還包含服務(wù)器級別的工作管理器,這些工作管理器可提供優(yōu)先級和線程管理。這些可以通過全局方式進行配置,也可以針對應(yīng)用程序的特定模塊進行配置。
雖然 commonj.timer 和 commonj.work 屬于同一個 API 的一部分,但它們的功能卻各不相同。您可以根據(jù)應(yīng)用程序的特定需要實現(xiàn)其中的一種。CommonJ 計時器 API 適用于按特定間隔調(diào)度工作的情形;例如,您知道某一項作業(yè)應(yīng)在特定時間運行的情形。而 CommonJ 工作 API 適用于根據(jù)優(yōu)先級處理工作的情形。例如,您不能準確預(yù)測一項特定作業(yè)的發(fā)生時間,而是希望這項作業(yè)被賦予更高或更低的優(yōu)先級。
下列部分將詳細描述 CommonJ API。
?
?
計時器 API 概述
計時器 API 包含以下三個接口:
計時器管理器提供在受管環(huán)境中創(chuàng)建和使用計時器的框架。計時器監(jiān)聽器接收計時器通知。TimerManager.schedule() 方法用于調(diào)度 TimerListener,使其在特定時間或間隔運行。
有關(guān)如何實現(xiàn)計時器的詳細描述,請參閱使用計時器 API。
TimerManager 接口
TimerManager 接口在應(yīng)用程序中提供常規(guī)調(diào)度框架。受管的環(huán)境可以支持多個 TimerManager 實例。這就是說,一個應(yīng)用程序可以包含多個 TimerManager 實例。
創(chuàng)建和配置計時器管理器
可通過部署描述符在部署期間配置 TimerManager。TimerManager 定義還可以包含其他實現(xiàn)特定的配置信息。
一旦在部署描述符中定義了 TimerManager,您就可以在本地 Java 環(huán)境中使用 JNDI 查找訪問它的實例。每次調(diào)用 JNDI lookup() 訪問 TimerManager 時,都將返回 TimerManager 的一個新邏輯實例。
TimerManager 接口是線程安全的。
有關(guān)使用 JNDI 的詳細信息,請參閱"WebLogic JNDI 編程"。
掛起 TimerManager
可使用 suspend() 和 resume() 方法,掛起和恢復 TimerManager。當掛起 TimerManager 時,所有待定的計時器將延遲到 TimerManager 恢復時為止。
停止 TimerManager
可使用 stop() 方法停止 TimerManager。在調(diào)用 stop() 方法后,所有活動的計時器都將停止,而且 TimerManager 實例將停止監(jiān)視所有 TimerListener 實例。
TimerListener 接口
使用?commonj.timers?包的所有應(yīng)用程序都需要實現(xiàn) TimerListener 接口。
Timer 接口
當通過 TimerManager 調(diào)度計時器時,將返回 Timer 接口的實例。
?
?
使用計時器 API
此部分將簡述在應(yīng)用程序中使用計時器 API 時的必需步驟。
在部署應(yīng)用程序前,確保已創(chuàng)建了包含計時器管理器資源引用的部署描述符。
這樣可以通過 JNDI 訪問 TimerManager。有關(guān) JNDI 查找的詳細信息,請參閱"WebLogic JNDI 編程"。
下面描述計時器 API 的實現(xiàn)過程:
創(chuàng)建一個 InitialContext,以便在 JNDI 中查找 TimerManager。
IntialContext inctxt = new InitialContext();
有關(guān) JNDI 查找的詳細信息,請參閱"WebLogic JNDI 編程"。
基于 TimerManager 的 JNDI 查找,新建一個 TimerManager。
TimerManager mgr = (TimerManager)ctx.lookup(`java:comp/env/timer/MyTimer');
在此語句中,將 JNDI 查找結(jié)果強制轉(zhuǎn)換成 TimerManager。
實現(xiàn) TimerListener 來接收計時器通知。
TimerListener listener = new StockQuoteTimerListener(`abc', `example');
調(diào)用 TimerManager.schedule()
mgr.schedule(listener, 0, 1000*60)
schedule() 方法返回計時器對象。
實現(xiàn) timerExpired() 方法
public void timerExpired(Timer timer) {
?????//此方法執(zhí)行
?????//業(yè)務(wù)邏輯
}
計時器管理器示例
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 {
/**
??* 非常簡單地實現(xiàn)服務(wù)方法
??* 該實現(xiàn)安排了 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 秒執(zhí)行一次計時器
??????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();
????}
??}
}
?
?
使用作業(yè)調(diào)度程序
此部分描述作業(yè)調(diào)度程序功能的用法。通過作業(yè)調(diào)度程序,您可以在群集環(huán)境中實現(xiàn) commonj.timer API。
作業(yè)調(diào)度程序?qū)嶋H上就是可以在群集中使用的 commonj.timer API 包的實現(xiàn)。在此上下文,作業(yè)被定義為要提交給作業(yè)調(diào)度程序進行執(zhí)行的 commonj.timers.TimerListener 實例。
本部分包含下列主題:
計時器的生命周期
在應(yīng)用程序中實現(xiàn) commonj.timer API 時,可以為計時器配置兩種可能的生命周期。
本地計時器在單個服務(wù)器 JVM 中調(diào)度,并且這些計時器在它們整個生命期中都是在此 JVM 中進行處理。只要 JVM 運行,計時器就將一直運行;而當 JVM 退出時,計時器將出現(xiàn)故障。在服務(wù)器啟動后,應(yīng)用程序負責重新調(diào)度計時器。
此為 commonj.timers 的基本實現(xiàn),其描述見計時器 API 概述。
群集范圍的計時器了解包含群集中每一服務(wù)器的其他 JVM,因此能執(zhí)行負載平衡和故障轉(zhuǎn)移。群集范圍計時器的生命周期不與創(chuàng)建它的服務(wù)器綁定在一起,但是在群集的整個生命周期繼續(xù)發(fā)揮作用。只要還有一個群集成員處于活動狀態(tài),計時器就會繼續(xù)發(fā)揮作用。此功能稱為作業(yè)調(diào)度程序。
每一計時器有其自己的優(yōu)缺點。本地計時器能以短得多的作業(yè)處理時間間隔處理作業(yè)。由于群集有持久性要求,因此作業(yè)調(diào)度程序不能如此精確地處理作業(yè)。另一方面,作業(yè)調(diào)度程序更適合于在即使創(chuàng)建任務(wù)的初始服務(wù)器出現(xiàn)故障的情況下也必須執(zhí)行的任務(wù)。
實現(xiàn)和配置作業(yè)調(diào)度程序
此部分將簡述在應(yīng)用程序中實現(xiàn)作業(yè)調(diào)度程序的基本過程以及配置 WebLogic Server 環(huán)境以利用作業(yè)調(diào)度程序的基本過程。
數(shù)據(jù)庫配置
為了維持持久性,并使計時器支持群集,作業(yè)調(diào)度程序需要數(shù)據(jù)庫連接。作業(yè)調(diào)度程序功能與服務(wù)器遷移支持相同的數(shù)據(jù)庫供應(yīng)商和版本。
為方便起見,可與會話持久性、服務(wù)器遷移等使用相同的數(shù)據(jù)庫。
在數(shù)據(jù)庫中,必須基于以下模式創(chuàng)建一個稱為 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)
)
數(shù)據(jù)源配置
在創(chuàng)建了采用所需模式的表之后,必須定義一個可在群集配置內(nèi)引用的數(shù)據(jù)源。只有為 Cluster MBean 的 DataSourceForJobScheduler 特性定義了有效數(shù)據(jù)源后,才能使用作業(yè)調(diào)度程序功能。您可以在 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>
作業(yè)調(diào)度程序中的 JNDI 訪問
與常規(guī) commonj.timer API 相比,在群集計時器中執(zhí)行 JNDI 查找的過程有所不同。下面的代碼段說明如何將 JNDI 查找強制轉(zhuǎn)換成 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 秒執(zhí)行一次此作業(yè)
不支持的方法和接口
作業(yè)調(diào)度程序環(huán)境并非支持 commonj.timer API 的所有方法和接口。不支持下列方法和接口:
?
?
工作管理器 API 的描述
工作管理器 (commonj.work) API 提供的接口允許應(yīng)用程序在一個容器中并發(fā)地執(zhí)行多個工作項。
實際上,此 API 就是 java.lang.Thread API 的容器管理替代方法。java.lang.Thread API 不適用于受管 Java EE 環(huán)境中承載的應(yīng)用程序。在這樣的環(huán)境中,工作管理器 API 替代方法的效果更好,因為它允許容器全面查看和控制所有執(zhí)行線程。
注意: | 工作管理器 API 不提供故障轉(zhuǎn)移和持久性機制。如果受管服務(wù)器環(huán)境出現(xiàn)故障或關(guān)閉,則當前所有工作都將丟失。 |
工作管理器接口
此部分概述工作管理器 API 中定義的接口。有關(guān)使用這些接口的詳細信息,請參閱?commonj.work package?的 javadoc。
工作管理器 API 包含下列接口:
WorkManager?- 此接口提供一組用于調(diào)度要執(zhí)行工作的調(diào)度方法。
系統(tǒng)管理員可在服務(wù)器級別定義 WorkManager。WorkManager 實例通過執(zhí)行 JNDI 查找來獲取。受管的環(huán)境可以支持多個 WorkManager 實例。請參閱"WebLogic JNDI 編程"。您在部署期間將 WorkManager 配置為 resource-ref。請參閱工作管理器部署。
每個 WorkManager 實例在應(yīng)用程序級別返回一個 WorkItem。有關(guān)在應(yīng)用程序中實現(xiàn) WorkManager 的詳細信息,請參閱?WorkManager?javadocs。
Work?- 通過此接口,您可以異步運行應(yīng)用程序代碼。通過創(chuàng)建實現(xiàn)此接口的類,您可以創(chuàng)建可通過調(diào)度在特定的時間或定義的間隔運行的代碼塊。換句話說,此為在工作管理器 API 中處理的"工作"。
WorkItem?- 在將?Work?實例提交給 WorkManager 后,WorkManager 將返回一個 WorkItem。此 WorkItem 用于確定整個 Work 實例的狀態(tài)。
WorkListener?- WorkListener 接口是一個回調(diào)接口,它在 WorkManager 與 Work 實例中定義的調(diào)度工作之間建立通信。
可以使用 WorkListener 確定 Work 項的當前狀態(tài)。有關(guān)詳細信息,請參閱?WorkListener?javadocs。
注意: | WorkListener 實例總與通過 WorkManager 調(diào)度 Work 的初始線程在同一個 JVM 中執(zhí)行。 |
WorkEvent?- 在 WorkManager 處理 Work 時,會將 WorkEvent 發(fā)送給 WorkListener。
RemoteWorkItem?- RemoteWorkItem 接口是 WorkItem 接口的擴展,可用于在遠程執(zhí)行工作。通過此接口,可序列化工作可以在群集中的任何成員上執(zhí)行。
工作管理器部署
在適當部署描述符中通過 resource-ref 在服務(wù)器級別定義工作管理器。在其他描述符中可以是?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>");
// 不要關(guān)閉輸出流 - 而是啟用 servlet 引擎關(guān)閉輸出流
// 以實現(xiàn)更佳性能。
System.out.println("finished execution");}
}
?
posted on 2012-02-19 19:23
BeanSoft 閱讀(4888)
評論(0) 編輯 收藏 所屬分類:
WebLogic