當我們的業務流程被設計開發完畢之後,會有許多相關的文件"散落"在工程中,其中包括:
定義流程的JPDL文件
根據圖形化流程定義同步生成的流程圖片文件(PNG格式)
業務流程中用於人機交互的表單頁面文件
事件監聽器等用戶自定義代碼的Java類文件
其他流程資源文件,例如小圖標、css樣式表、腳本文件、屬性文件等
jbpm4支持將流程定義及其相關資源打包一個JAR(Java歸檔)格式的文件,部署到服務器上(其實就是服務所連接的JBPM數據庫中),然後流程定義就可以被執行了。
一、如何將流程定義和流程相關資源部署到jbpm數據庫中?
jbpm4提供了一個基於Ant任務的API來部署業務流程歸檔——
org.jbpm.pvm.internal.ant.JbpmDeployTask。
JbpmDeployTask不僅可以部署單個業務流程歸檔,也可以部署一組業務流程歸檔到服務器上。通過讀取jbpm.cfg.xml中的jdbc數據連接信息將業務流程歸檔部署到數據庫中。因此,在使用JbpmDeployTask部署流程定義之前,先確保部署的數據庫正在運行。
創建和部署業務流程歸檔的例子位於jbpm4發佈包中的examples目錄下的Ant build.xml中,任務名稱是create.and.deploy.examples。
該Ant所解決的問題如下:在examples/build.xml中
1>需要聲明一個path任務來指定包含JbpmDeployTask的jbpm.jar及其所有的依賴庫。
2>需要創建一個業務流程歸檔,可以使用Ant的jar任務
注意:工作流引擎掃描業務流程歸檔中所有以.jpdl.xml結尾的文件,所有這些文件的內容都會被當做JPDL流程定義來解析,然後被用來發起流程實例,業務流程歸檔中所有其他資源也會在部署過程中持久化到數據庫中。
所有這些資源被統一編號保存在數據庫表jbpm4_lob中,因此可以很方便地通過jbpm4提供的RepositoryService.getResourceAsStream API隨時訪問這些資源。
3>部署,需要先在Ant中將JbpmDeployTask生命一個jbpm-deploy的自定義任務
4>調用這個自定義的Ant任務
通過查看org.jbpm.pvm.internal.ant.JbpmDeployTask類的源碼,可以發現爲我們預留了3個接口參數
private String jbpmCfg; private File file; private List<FileSet> fileSets = new ArrayList<FileSet>();
file:指定需要被部署的業務流程定義文件;以.xml結尾的文件會被作爲流程定義文件直接部署;
以"*ar"結尾的文件,比如.bar或.jar文件,則會作爲業務流程歸檔部署。
jbpmCfg:指定jbpm配置文件,默認尋找classpath根目錄下的jbpm.cfg.xml如果需要自定義,這個路徑位於jbpm-deploy任務定義的classpath範圍內。
fileSets:指定需要被部署的業務流程定義文件集合。
二、部署流程Java類的2種方式
把Java類部署到應用服務器類庫中,例如在Tomcat服務器的lib目錄中部署流程Java類的jar包。這種方式加載類的優先級最高。
把流程Java類部署到Web應用或企業應用相應目錄中,例如WEB-INF、classes目錄或WEB-INF/lib目錄。Tomcat在運行時會找到流程所需的Java類並調用。這種方式加載類的優先級爲次高。
三、示例:部署業務流程定義
首先配置好JBPM運行環境,即在classpath根目錄下的jbpm.hibernate.cfg.xml中設置好數據庫連接,並確保數據庫服務正常。
第一種流程定義方式:
1>通過執行Ant腳本的方式進行部署,這需要將要部署的流程定義及其相關資源按照classpath的層次結構打包歸檔,假設業務流程歸檔爲process.jar,則部署process.jar的Ant腳本如下:
<project name="jbpm.examples.process.deployment"> <!--使用jbpm.home表示JBPM4的安裝目錄--> <property file="jbpm.home" value="D:/jbpm-4.4" /> <!--這個Ant任務專門用來定義JBPM的運行庫、依賴庫以及配置文件的classpath路徑--> <target name="jbpm.libs.path"> <path id="jbpm.libs.incl.dependencies"> <pathelement location="${jbpm.home}/examples/bin" /> <pathelement location="${jbpm.home}/jbpm.jar" /> <fileset dir="${jbpm.home}/lib" includes="*.jar" /> </path> </target> <target name="process.jar" depends="jbpm.libs.path"> </target> <!--使用JBPM4工作流引擎提供的Ant API——JbpmDeployTask來執行部署--> <target name="create.and.deploy.example" depends="jbpm.libs.path,process.jar"> <taskdef name="jbpm-deploy" classname="org.jbpm.pvm.internal.ant.JbpmDeployTask" classpathref="jbpm.libs.incl.dependencies"/> <!--指定流程定義打包文件--> <jbpm-deploy file="process.jar"/> </target> </project>
2>執行Ant任務create.and.deploy.examples即可部署流程定義打包process.jar至jbpm數據庫中
第二種流程定義方式:
通過編寫Java代碼直接調用JBPM工作流引擎提供的部署服務API完成流程定義部署。
//JbpmTestCase繼承了JUnit的TestCase類,是JBPM對Junit框架的擴展 public class Test extends JbpmTestCase { //保存流程定義的部署ID String deploymentId; @Override protected void setUp() throws Exception { super.setUp(); //使用RepositoryService提供的API方法從classpath中部署流程定義 deploymentId = repositoryService.createDeployment() .addResourceFromClasspath("produce.jpdl.xml").deploy(); } @Override protected void tearDown() throws Exception { //該方法會物理清楚deployementId對應的流程定義及其所有相關資源, //並關聯清除基於此流程定義的流程實例、活動實例、任務、歷史流程實例等所有運行時及歷史的流程實體記錄 repositoryService.deleteDeployment(deploymentId); super.tearDown(); } public void test(){ //@Todo } }
注意:
在以上單元測試中流程引擎服務(RepositoryService)的初始化工作室由JbpmTestCase.setUp方法完成的,爲此定義了6個流程引擎服務:
protected ProcessEngine processEngine; //資源庫服務 protected RepositoryService repositoryService; //執行服務 protected ExecutionService executionService; //管理服務 protected ManagementService managementService; //任務服務 protected TaskService taskService; //歷史服務 protected HistoryService historyService; //身份認證服務 protected IdentityService identityService;
而JbpmTestCase在其setUp方法中初始化:
@Override protected void setUp() throws Exception { super.setUp(); processEngine = buildProcessEngine(); repositoryService = processEngine.getRepositoryService(); executionService = processEngine.getExecutionService(); historyService = processEngine.getHistoryService(); managementService = processEngine.getManagementService(); taskService = processEngine.getTaskService(); identityService = processEngine.getIdentityService(); }