想用activiti玩转中国式流程,单纯依靠普通的XXXService的api是不够的,必须要深入到数据库以及流程虚拟机的层面,修改数据库以及流程虚拟机对象,才能实现加签、减签、驳回、自由跳转之类的操作。另外,由于直接操作数据库很可能会有遗漏或者误操作,因此比较靠谱的方法是调用那些处于“中层”的api。“高层”的api就是XXXService的api,“底层”的是实体管理类的api。要熟悉这些“中层”api,需要看看源码中,activiti是如何调用这些api,这些api具体又做了什么。这样才能比较安全地处理这些中国式流程。
在《activiti学习(九)——对象解析器原理》中,其实已经对流程虚拟机有一个初步的探索。流程虚拟机,简单说就是按照规则,从起始点出发,通过连线解析后的对象TransitionImpl,走到指向的活动解析后的ActivityImpl,然后执行该ActivityImpl对应的行为。然后再离开这个ActivityImpl,通过TransitionImpl走到下一个ActivityImpl,然后执行其行为,如此类推。
本文主要分析流程虚拟机主要类的架构,即ActivityImpl、TransitionImpl以及它们的父类、接口的架构。本文比较适合一边研究流程虚拟机源码,一边对照着这些类和接口来看。我一开始看流程虚拟机,常常会看晕,搞不清楚具体在查什么,在执行什么,在调用什么。如果一开始看这些类的架构,可能也没什么特别的感觉。本文的作用是先对这些类有个大概的印象。
上图是流程虚拟机主要类的类图。上图看似挺复杂,下面我们分析一下主要的类及其作用,其实并不复杂。
PvmProcessElement接口:
public interface PvmProcessElement extends Serializable {
String getId();
PvmProcessDefinition getProcessDefinition();
Object getProperty(String name);
}
PvmProcessElement接口是最顶层的接口。通过上述声明的方法可以看到,对于每个ActivityImpl和TransitionImpl,我们都可以getId方法获取其id,通过getProcessDefinition方法获取其所在流程的流程定义,通过getProperty获取其属性。
ProcessElementImpl类:
public class ProcessElementImpl implements PvmProcessElement {
protected String id;
protected ProcessDefinitionImpl processDefinition;
protected Map<String, Object> properties;
//......省略
}
ProcessElementImpl类是PvmProcessElement接口的具体实现。
ScopeImpl类:
public abstract class ScopeImpl extends ProcessElementImpl implements PvmScope {
protected List<ActivityImpl> activities = new ArrayList<ActivityImpl>();
protected Map<String, ActivityImpl> namedActivities = new HashMap<String, ActivityImpl>();
protected Map<String, List<ExecutionListener>> executionListeners = new HashMap<String, List<ExecutionListener>>();
protected IOSpecification ioSpecification;
public ScopeImpl(String id, ProcessDefinitionImpl processDefinition) {
super(id, processDefinition);
}
public ActivityImpl findActivity(String activityId) {
//......
}
public ActivityImpl createActivity(String activityId) {
//......
}
public boolean contains(ActivityImpl activity) {
//......
}
public void addExecutionListener(String eventName, ExecutionListener executionListener, int index) {
//......
}
//......
}
ScopeImpl是一个比较重要的类。上面的代码省略了很多。这个类的属性和方法大多涉及到Process这个元素。activities属性表示它包含的所有ActivityImpl。namedActivities属性是用于通过id找到对应ActivityImpl的Map,与findActivity方法相关。executionListeners是执行监听器的集合。ioSpecification属性与流程文档的DataInput、DataOutput相关。其中findActivity是我所说的“中层”api常会用到方法。
ProcessDefinitionImpl类:
public class ProcessDefinitionImpl extends ScopeImpl implements PvmProcessDefinition {
protected String name;
protected String key;
protected String description;
protected ActivityImpl initial;
protected Map<ActivityImpl, List<ActivityImpl>> initialActivityStacks = new HashMap<ActivityImpl, List<ActivityImpl>>();
protected List<LaneSet> laneSets;
protected ParticipantProcess participantProcess;
public ProcessDefinitionImpl(String id) {
super(id, null);
processDefinition = this;
}
public PvmProcessInstance createProcessInstance() {
if(initial == null) {
throw new ActivitiException("Process '"+name+"' has no default start activity (e.g. none start event), hence you cannot use 'startProcessInstanceBy...' but have to start it using one of the modeled start events (e.g. message start events).");
}
return createProcessInstanceForInitial(initial);
}
public PvmProcessInstance createProcessInstanceForInitial(ActivityImpl initial) {
//......
}
public synchronized List<ActivityImpl> getInitialActivityStack(ActivityImpl startActivity) {
//......
}
//......
}
ProcessElementImpl类中initial属性代表流程起始的活动,通常对应流程的startEvent。createProcessInstanceForInitial是启动流程时调用的方法。
ActivityImpl类:
public class ActivityImpl extends ScopeImpl implements PvmActivity, HasDIBounds {
protected List<TransitionImpl> outgoingTransitions = new ArrayList<TransitionImpl>();
protected Map<String, TransitionImpl> namedOutgoingTransitions = new HashMap<String, TransitionImpl>();
protected Map<String, Object> variables;
protected List<TransitionImpl> incomingTransitions = new ArrayList<TransitionImpl>();
protected ActivityBehavior activityBehavior;
protected ScopeImpl parent;
protected boolean isScope;
protected boolean isAsync;
protected boolean isExclusive;
protected String failedJobRetryTimeCycleValue;
protected int x = -1;
protected int y = -1;
protected int width = -1;
protected int height = -1;
public ActivityImpl(String id, ProcessDefinitionImpl processDefinition) {
super(id, processDefinition);
}
public TransitionImpl createOutgoingTransition(String transitionId, Expression skipExpression) {
//......
}
public TransitionImpl findOutgoingTransition(String transitionId) {
return namedOutgoingTransitions.get(transitionId);
}
//......
}
outgoingTransitions属性为从这个活动节点出去的线的集合,即“出线”的集合。namedOutgoingTransitions为一个根据“出线”的id为key、“出线”为value的map对象,方便快速找出对应“出线”。incomingTransitions为“进线”的集合。activityBehavior属性代表这个活动对应的“行为”。即流程运行到改节点时,节点会做什么,当用户调用某些方法时,节点又会进行什么处理。“行为”是activiti节点的核心。另外通过上面createOutgoingTransition、findOutgoingTransition方法可以看出,连线的对象是通过ActivityImpl进行创建的。
TransitionImpl类
public class TransitionImpl extends ProcessElementImpl implements PvmTransition {
protected ActivityImpl source;
protected ActivityImpl destination;
protected List<ExecutionListener> executionListeners;
protected Expression skipExpression;
//......
}
source属性为连线的起始节点,destination为连线的终止节点。executionListeners为执行监听器集合。skipExpression为自动跳过表达式。