想用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爲自動跳過表達式。