整体来说实现的非常清晰:
1、引擎解析流程定义xml时,给相应的事件挂接上create-timer 和 cancel-timer动作
2、流程实例实际运转时,create-timer动作在相应事件触发时执行
3、create-timer在job表里插入相应时间job记录,给该job记录附上计算完毕的执行时间
4、JobExecutorServlet在后台启动一到多个JobExecutorThread线程
5、JobExecutorThread线程不停的每隔一段时间对job表扫描一次,找出需要执行的job记录,执行之
6、只执行一次的job记录,执行完毕后删除之;重复执行的job记录,写入新的执行时间,更新之
7、相应事件触发cancel-timer动作,将对应job记录从job表里删除
下面具体用代码来说话(挂接到node节点):
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节点解析成了两个ACTION:CreateTimerAction和CancelTimerAction
CreateTimerAction会在进入该节点时触发,而CancelTimerAction会在令牌离开该节点时触发。
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的执行时间。
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表里获得将要执行的job记录
if (! acquiredJobs.isEmpty()) { //如果记录不为空,则开始执行
Iterator iter = acquiredJobs.iterator();
while (iter.hasNext() && isActive) {
Job job = (Job) iter.next();
executeJob(job); //执行
}
} else { // no jobs acquired //如果没有可执行的job,则等待一段时间
if (isActive) {
long waitPeriod = getWaitPeriod(); //等待的时间是找出即将执行的job离现在最近的时间间隔
if (waitPeriod>0) {
synchronized(jobExecutor) {
jobExecutor.wait(waitPeriod);
}
}
}
}
.
} catch (Throwable t) {
t.printStackTrace();
} finally {
log.info(getName()+" leaves cyberspace");
}
}
看看实际执行的方法
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对象本身去完成执行的逻辑,并决定是否删除job记录
jobSession.deleteJob(job);
}
.
}
5、着重关注Time对象
在上面我们看到实际执行的代码是job.execute(jbpmContext);
Time 是Job的子类,看看它的实现:
public boolean execute(JbpmContext jbpmContext) throws Exception {
boolean deleteThisJob = true; //执行完毕后是否删除job记录
ExecutionContext executionContext = new ExecutionContext(token);
executionContext.setTimer(this);
if (taskInstance!=null) {
executionContext.setTaskInstance(taskInstance);
}
// 触发timer事件
if (graphElement!=null) {
graphElement.fireAndPropagateEvent(Event.EVENTTYPE_TIMER, executionContext);
}
// 如果timer节点上挂有action则执行之
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记录不容许删除,同时计算新的执行时间
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.blogjava.net/ronghao 荣浩原创,转载请注明出处:)
posted on 2007-06-22 17:13
ronghao 阅读(1939)
评论(0) 编辑 收藏 所属分类:
工作流jbpm3