posts - 193,  comments - 520,  trackbacks - 0
  整体来说实现的非常清晰:
  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 阅读(1940) 评论(0)  编辑  收藏 所属分类: 工作流jbpm3

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


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问  
 
<2007年6月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

关注工作流和企业业务流程改进。现就职于ThoughtWorks。新浪微博:http://weibo.com/ronghao100

常用链接

留言簿(38)

随笔分类

随笔档案

文章分类

文章档案

常去的网站

搜索

  •  

最新评论

阅读排行榜

评论排行榜