整體來說實現(xiàn)的非常清晰:
1、引擎解析流程定義xml時,給相應的事件掛接上create-timer 和 cancel-timer動作
2、流程實例實際運轉時,create-timer動作在相應事件觸發(fā)時執(zhí)行
3、create-timer在job表里插入相應時間job記錄,給該job記錄附上計算完畢的執(zhí)行時間
4、JobExecutorServlet在后臺啟動一到多個JobExecutorThread線程
5、JobExecutorThread線程不停的每隔一段時間對job表掃描一次,找出需要執(zhí)行的job記錄,執(zhí)行之
6、只執(zhí)行一次的job記錄,執(zhí)行完畢后刪除之;重復執(zhí)行的job記錄,寫入新的執(zhí)行時間,更新之
7、相應事件觸發(fā)cancel-timer動作,將對應job記錄從job表里刪除
下面具體用代碼來說話(掛接到node節(jié)點):
1、引擎解析流程定義xml
JpdlXmlReader.java
protected void readNodeTimer(Element timerElement, Node node) {
String name = timerElement.attributeValue("name", node.getName());
CreateTimerAction createTimerAction = new CreateTimerAction();
createTimerAction.read(timerElement, this);
createTimerAction.setTimerName(name);
createTimerAction.setTimerAction(readSingleAction(timerElement));
addAction(node, Event.EVENTTYPE_NODE_ENTER, createTimerAction);
CancelTimerAction cancelTimerAction = new CancelTimerAction();
cancelTimerAction.setTimerName(name);
addAction(node, Event.EVENTTYPE_NODE_LEAVE, cancelTimerAction);
}
可以看到,引擎把xml中timer節(jié)點解析成了兩個ACTION:CreateTimerAction和CancelTimerAction
CreateTimerAction會在進入該節(jié)點時觸發(fā),而CancelTimerAction會在令牌離開該節(jié)點時觸發(fā)。
2、看看CreateTimerAction和CancelTimerAction究竟在做些什么
CreateTimerAction.java
public void execute(ExecutionContext executionContext) throws Exception {
Timer timer = createTimer(executionContext);
SchedulerService schedulerService = (SchedulerService) Services.getCurrentService(Services.SERVICENAME_SCHEDULER);
schedulerService.createTimer(timer);
}
很明顯,是通過一個職責集中的schedulerService向job表中插入了一條job記錄,注意到這個方法:
protected Timer createTimer(ExecutionContext executionContext) {
Timer timer = new Timer(executionContext.getToken());
.
if (dueDate!=null) {
Duration duration = new Duration(dueDate);
Date dueDateDate = businessCalendar.add( new Date(), duration );
timer.setDueDate(dueDateDate);
}
.
return timer;
}
這里利用JBPM提供的工作時間計算組件計算了job的執(zhí)行時間。
CancelTimerAction就很簡單了,刪除相應的job記錄。
CancelTimerAction.java
public void execute(ExecutionContext executionContext) throws Exception {
SchedulerService schedulerService = (SchedulerService) Services.getCurrentService(Services.SERVICENAME_SCHEDULER);
schedulerService.deleteTimersByName(timerName, executionContext.getToken());
}
3、JobExecutorServlet是干什么的
啟動線程
public void init() throws ServletException {
.
jbpmConfiguration.startJobExecutor();
}
4、線程是如何工作
public void run() {
try {
currentIdleInterval = idleInterval;
while (isActive) {
try {
Collection acquiredJobs = acquireJobs(); //從job表里獲得將要執(zhí)行的job記錄
if (! acquiredJobs.isEmpty()) { //如果記錄不為空,則開始執(zhí)行
Iterator iter = acquiredJobs.iterator();
while (iter.hasNext() && isActive) {
Job job = (Job) iter.next();
executeJob(job); //執(zhí)行
}
} else { // no jobs acquired //如果沒有可執(zhí)行的job,則等待一段時間
if (isActive) {
long waitPeriod = getWaitPeriod(); //等待的時間是找出即將執(zhí)行的job離現(xiàn)在最近的時間間隔
if (waitPeriod>0) {
synchronized(jobExecutor) {
jobExecutor.wait(waitPeriod);
}
}
}
}
.
} catch (Throwable t) {
t.printStackTrace();
} finally {
log.info(getName()+" leaves cyberspace");
}
}
看看實際執(zhí)行的方法
protected void executeJob(Job job) {
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
JobSession jobSession = jbpmContext.getJobSession();
job = jobSession.loadJob(job.getId());
try {
log.debug("executing job "+job);
if (job.execute(jbpmContext)) { //交由Job對象本身去完成執(zhí)行的邏輯,并決定是否刪除job記錄
jobSession.deleteJob(job);
}
.
}
5、著重關注Time對象
在上面我們看到實際執(zhí)行的代碼是job.execute(jbpmContext);
Time 是Job的子類,看看它的實現(xiàn):
public boolean execute(JbpmContext jbpmContext) throws Exception {
boolean deleteThisJob = true; //執(zhí)行完畢后是否刪除job記錄
ExecutionContext executionContext = new ExecutionContext(token);
executionContext.setTimer(this);
if (taskInstance!=null) {
executionContext.setTaskInstance(taskInstance);
}
// 觸發(fā)timer事件
if (graphElement!=null) {
graphElement.fireAndPropagateEvent(Event.EVENTTYPE_TIMER, executionContext);
}
// 如果timer節(jié)點上掛有action則執(zhí)行之
if (action!=null) {
try {
log.debug("executing timer '"+this+"'");
action.execute(executionContext);
} catch (Exception actionException) {
.
}
// 如果定義了transition屬性,則流程順著定義的路徑流轉
if ( (transitionName!=null)
&& (exception==null) // and if no unhandled exception occurred during the action
) {
if (token.getNode().hasLeavingTransition(transitionName)) {
token.signal(transitionName);
}
}
// 如果定義了repeat屬性則job記錄不容許刪除,同時計算新的執(zhí)行時間
if (repeat!=null) {
deleteThisJob = false;
while (dueDate.getTime()<=System.currentTimeMillis()) {
dueDate = businessCalendar
.add(dueDate,
new Duration(repeat));
}
log.debug("updated timer for repetition '"+this+"' in '"+(dueDate.getTime()-System.currentTimeMillis())+"' millis");
}
return deleteThisJob;
}
http://www.tkk7.com/ronghao 榮浩原創(chuàng),轉載請注明出處:)
posted on 2007-06-22 17:13
ronghao 閱讀(1947)
評論(0) 編輯 收藏 所屬分類:
工作流jbpm3