[JBPM3.2]Swimlane方式的任务分配

    JBPM3的任务分配方式主要由以下几种:
(1)直接设置actor-id属性,既可以设置固定的任务处理人,如actor-id='dinguangx'(这种情况在实际开发中极少用到的吧);也可以从流程变量中取出任务处理人,如actor-id="#{actorid}".
(2)通过TaskInstance实例直接调用API方法设置,如ti.setActor("dinguangx");;
(3)通过AssignmentHandler在任务创建的时候分配任务;这是最为常用的一种方式,也是最灵活的一种任务分配方式,可以在任务分配的时候做一些其他的操作;
(4)通过Swimlane的方式分配任务.通过第(3)种方式来分配任务时,虽然灵活,但是如果要将多个任务分配给同一个处理人时我们不得不编写多个handler类,造成java类的过度膨胀;这时候就可以通过Swimlane的方式来分配任务,多个相同处理人的Task结点只引用定义好的Swimlane就可以完成任务分配。
    这里主要来分析一下使用Swimlane来实现任务分配的过程。
    TaskInstance类中的assign(ExecutionContext)方法实现了任务的分配,下面的这段代码取自于TaskInstance类的源码.
public void assign(ExecutionContext executionContext) {
    TaskMgmtInstance taskMgmtInstance = executionContext.getTaskMgmtInstance();
    
    Swimlane swimlane = task.getSwimlane();
    // if this task is in a swimlane
    if (swimlane!=null) {
      
      // if this is a task assignment for a start-state
      if (isStartTaskInstance()) {
        // initialize the swimlane
        swimlaneInstance = new SwimlaneInstance(swimlane);
        taskMgmtInstance.addSwimlaneInstance(swimlaneInstance);
        // with the current authenticated actor
        swimlaneInstance.setActorId(SecurityHelper.getAuthenticatedActorId());
        
      } else {
        
        // lazy initialize the swimlane...
        // get the swimlane instance (if there is any) 
        swimlaneInstance = taskMgmtInstance.getInitializedSwimlaneInstance(executionContext, swimlane);
        
        // copy the swimlaneInstance assignment into the taskInstance assignment
        copySwimlaneInstanceAssignment(swimlaneInstance);
      }

    } else { // this task is not in a swimlane
      taskMgmtInstance.performAssignment(task.getAssignmentDelegation(), 
                                         task.getActorIdExpression(),
                                         task.getPooledActorsExpression(),
                                         this, 
                                         executionContext);
    }
    
    updatePooledActorsReferences(swimlaneInstance);
  }

    我们假设当前任务不是位于Start-state中,并且使用Swimlane的任务分配方式,即task.getSwimlane()不为空,且isStartTaskInstance()为false的情况。
    此时,代码将执行到
 swimlaneInstance = taskMgmtInstance.getInitializedSwimlaneInstance(executionContext, swimlane);

    再来看一下getInitializedSwimlaneInstance(ExecutionContext)方法执行的是什么工作:
public SwimlaneInstance getInitializedSwimlaneInstance(ExecutionContext executionContext, Swimlane swimlane) {
    // initialize the swimlane
    if (swimlaneInstances==null) swimlaneInstances = new HashMap();
    SwimlaneInstance swimlaneInstance = (SwimlaneInstance) swimlaneInstances.get(swimlane.getName());
    if (swimlaneInstance==null) {
      swimlaneInstance = new SwimlaneInstance(swimlane);
      addSwimlaneInstance(swimlaneInstance);
      // assign the swimlaneInstance
      performAssignment(swimlane.getAssignmentDelegation(), 
                        swimlane.getActorIdExpression(),
                        swimlane.getPooledActorsExpression(),
                        swimlaneInstance, 
                        executionContext);
    }

    return swimlaneInstance;
  }

    这个方法位于TaskMgmtInstance类中,而一个流程实例只对应一个TaskMgmtInstance实例,所以taskMgmtInstance实例中的swimlaneInstances将会包括流程实例中创建过的所有Swimlane实例。所以在getInitializedSwimlaneInstance方法执行时,如果任务是第一次被创建,将会根据设置的Swimlane创建一个新的SwimlaneInstance实例;否则就会在数据库中查询之前创建好的TaskInstance记录映射成TaskInstance对象返回给上一级调用过程。
再返回到assign()方法,紧跟着的处理代码是
copySwimlaneInstanceAssignment(swimlaneInstance);

    下面是copySwimlaneInstanceAssignment方法的代码:
public void copySwimlaneInstanceAssignment(SwimlaneInstance swimlaneInstance) {
    setSwimlaneInstance(swimlaneInstance);
    setActorId(swimlaneInstance.getActorId());
    setPooledActors(swimlaneInstance.getPooledActors());
  }
很容易理解,就是将SwimlaneInstance中的actorId,pooledActors分配给当前任务。
    注意到这里就存在一个问题,如果Task结点相应的任务不是第一次被创建,就不会再调用Swimlane的AssignmentHandler类来创建SwimlaneInstance。换句话说,Swimlane的AssignmentHandler类将只会被调用一次,而不是被多次调用,所以当流程用到Swimlane时(比如流程被审核退回再次提交审核时,审核结点就被多次执行到),AssignmentHandler类只执行一次,我们就不能在Swimlane中做额外的其他操作。比如,现在想把任务处理的URL设置在任务变量中,这个操作在AssignmentHandler类中进行;此时就会发现,当流程再次到达此结点时,任务变量中没有我们需要的值。原因也正在于此。
    所以,更准确地说,普通的AssignmentHandler方式每次都选择任务处理人,而Swimlane一旦创建之后,就把处理人绑定,之后的任务实例不能再选择处理人了。
    不过我们也可以利用它的这个特性实现一些其他的特殊业务.比如,一个共享的任务,如果被其中一个人选择处理,那么任务被退回之后再次到达此任务结点时,还应该由他来处理这个任务,就可以考虑通过设置SwimlaneInstance中的actorId来达到目的。

你可能感兴趣的:(工作)