最近在jBPM的諮詢/培訓中,客戶經常問到這麼一個問題:jBoss jBPM很好,可是它只能為我們提供一個工作流程引擎、一個業務流轉的機制,但它不能替我們處理業務問題、管理業務資料,如何才能將已開發好的特定業務系統和jBPM流程引擎結合在一起運行呢?
把jBPM流程系統和客戶業務系統整合在一起,歸根到底其實就是將流程運行過程中的任務執行個體(task instance)和業務執行個體(business instance)關聯起來,有兩種方法:
1. 在業務系統中儲存任務執行個體的引用,系統以業務為主導,能夠從一筆業務辦理中擷取它在流程中的位置等上下文資料。
2. 在jBPM流程系統中儲存業務執行個體的引用,系統以流程為主導,通過工作流程的工作清單向使用者提供業務任務,根據流程的任務執行個體的附加資料擷取其綁定的具體業務資料。
一般情況下,我推薦方法1,因為它對工作流程系統的沒有侵入,只需要修改業務系統,在業務表中加入一個列儲存task instance ID即可,這個步驟一般在業務系統設計階段預先構架好。
但是,在業務系統已經定型等情況下,要將已有的業務系統加入工作流程管理中,而且不侵入之,方法1明顯的就不合適了,那麼如何?方法2呢?還是有兩種思路:
1. 將業務系統的引用作為流程/任務執行個體的變數(process/task instance varialbes)儲存在jBPM系統中,那麼通過流程/任務執行個體即可根據其綁定的業務引用變數查詢業務執行個體資料。我們知道jBPM的變數系統是可以儲存任何可序列化的對象的,所以我們甚至可以將整個業務執行個體的java object儲存在jBPM工作流程系統中(這樣做可能比較瘋狂,因為資料庫存取位元據以及對象的序列/還原序列化都是很影響效率的)。
2. 這是jBPM官方推薦的一種思路,修改jBPM TaskInstance資料庫表!沒錯,就是修改jBPM的原始表結構、擴充它的原始碼。請注意我用的是擴充,因為這不會修改任何jBPM的源碼,而只是擴充之,這也是應用開源軟體的一個好習慣:不要修改它的原始碼,而是盡量利用它提供的機制去“擴充”出你需要的功能。
思路2的核心:首先在TaskInstance表中加一列,例如"BIZ_ID",用來儲存業務系統的引用,諸如“訂單ID”、“合約號”……
接著創造一個自訂的TaskInstance類,同時建立它的hbm描述檔案(不要說你不懂hibernate哦,那神仙也沒轍了),二者都需要繼承jBPM原始的TaskInstance定義,例如:
- public class CTaskInstance extends TaskInstance {
- private static final long serialVersionUID = 1270139435455649329L;
- protected String bizid;
- public CTaskInstance() {
- }
- public CTaskInstance(String taskName) {
- this.name = taskName;
- }
- public CTaskInstance(String taskName, String actorId) {
- this.name = taskName;
- this.actorId = actorId;
- }
- public String getBizid() {
- return bizid;
- }
- public void setBizid(String bizid) {
- this.bizid = bizid;
- }
- }
- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping auto-import="false" default-access="field">
- <subclass name="org.jbpm.customer.ctaskinstance.CTaskInstance"
- discriminator-value="C"
- extends="org.jbpm.taskmgmt.exe.TaskInstance">
- <property name="bizid" column="BIZID_" />
- </subclass>
- </hibernate-mapping>
接下來你覺得該做什麼呢?沒錯,將這個持久化類型的描述加入jBPM的hibernate.cfg.xml中,具體不表。
這時候,架構師們都會問:那如何讓jBPM系統知道我們自訂的任務執行個體,並且在流程運行時使用的是它而非原始的任務執行個體呢?所以,我們需要替換jbpm.cfg.xml中的jbpm.task.instance.factory屬性配置,將這個任務執行個體工廠替換為我們自己的實現,這下全明白了吧。
自訂任務執行個體工廠需要實現org.jbpm.taskmgmt.TaskInstanceFactory介面,例如:
- public class CTaskInstanceFactoryImpl implements TaskInstanceFactory {
- private static final long serialVersionUID = 1L;
- public TaskInstance createTaskInstance(ExecutionContext executionContext) {
- CTaskInstance ctaskin = new CTaskInstance();
- ctaskin
- .setBizid(new Date(System.currentTimeMillis())
- + "_U bizid here");
- return ctaskin;
- }
- }
此時,有經驗的看官還會有疑問:那麼在哪將我們的業務資料ID插入自訂任務執行個體呢?還是兩條路供選擇:-)
1. 參見上面TaskInstanceFactory的實現:可以在createTaskInstance時,設定業務資料ID,提示:可以通過ExecutionContext對象從流程執行個體變數中取得業務資料ID,從而滿足更加靈活的情境,當然你需要預先在流程執行個體中設定這個變數。
2. 可以通過編寫/設定task controller來為每個customer task instance在start和end時設定業務資料ID,同樣的,資料可以來自於流程執行個體預先綁定的變數。
那麼,當我們的customer task instance在持久化提交時,業務資料ID即可隨自訂任務執行個體對象存入資料庫。
在官方的user guide(3.2.3版本)中有這樣一段描述來簡單的說明如何為業務擴充任務執行個體,供各位看官參考:
12.10. Customizing task instances
Task instances can be customized. The easiest way to do this is
to create a subclass of TaskInstance. Then create a
org.jbpm.taskmgmt.TaskInstanceFactory implementation and
configure it by setting the configuration property jbpm.task.instance.factory
to the fully qualified class name in the jbpm.cfg.xml. If you use a subclass of
TaskInstance, also create a hibernate
mapping file for the subclass (using the hibernate
extends="org.jbpm.taskmgmt.exe.TaskInstance"). Then
add that mapping file to the list of mapping files in the
hibernate.cfg.xml
歡迎轉載,請註明作者:胡奇