jbpm_工作流框架笔记
1.?工作流基礎
1.1.?工作流相關概念
工作流(Workflow),就是“業務過程的部分或整體在計算機應用環境下的自動化”,它主要解決的是“使在多個參與者之間按照某種預定義的規則傳遞文檔、信息或任務的過程自動進行,從而實現某個預期的業務目標,或者促使此目標的實現”。
通俗的說,流程就是多個人在一起合作完成某件事情的步驟,把步驟變成計算機能理解的形式就是工作流。
工作流管理系統(WfMS,Workflow?Management?System)的主要功能是通過計算機技術的支持去定義、執行和管理工作流,協調工作流執行過程中工作之間以及群體成員之間的信息交互。工作流需要依靠工作流管理系統來實現。工作流管理系統是定義、創建、執行工作流的系統,應能提供以下三個方面的功能支持:
1.?定義工作流:包括具體的活動、規則等
2.?運行控制功能:在運行環境中管理工作流過程,對工作流過程中的活動進行調度
3.?運行交互功能:指在工作流運行中,WfMS與用戶(活動的參與者)及外部應用程序工具交互的功能。
一、?定義工作流
二、?執行工作流
采用工作流管理系統的優點
1.?提高系統的柔性,適應業務流程的變化?
2.?實現更好的業務過程控制,提高顧客服務質量
3.?降低系統開發和維護成本
工作流框架有:Jbpm、OSWorkflow、ActiveBPEL、YAWL等
OA(辦公自動化)主要技術之一就是工作流。
1.2.?開源工作流jBPM4.4介紹
jBPM?即java?Business?Process?Management,是基于java的業務流程管理系統。jBPM是市面上相當流行的一款開源工作流引擎,引擎底層基于Active?Diagram模型。jBPM4.4使用了hibernate(3.3.1版),因此可以很好的支持主流數據庫。jBPM4.4共有18張表。
jBPM官方主頁:http://www.jboss.org/jbpm
2.?準備jBPM4.4環境
2.1.?jBPM4.4所需環境
jBPM?requires?a?JDK?(standard?java)?version?5?or?higher.?http://java.sun.com/javase/downloads/index.jsp?
To?execute?the?ant?scripts,?you'll?need?apache?ant?version?1.7.0?or?higher:?http://ant.apache.org/bindownload.cgi
2.2.?下載相關資源
1,?jBPM下載地址:http://sourceforge.net/projects/jbpm/files/
2,?Eclipse下載地址(?Eclipse?IDE?for?Java?EE?Developers?(163?MB),Version:3.5?):http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/galileo
2.3.?安裝流程設計器(GPD,Eclipse插件)
GPD(Graphical?Process?Designer)是一個Eclipse插件。
安裝方法說明(jBPM4.4User?Guide,?2.11.2.?Install?the?GPD?plugin?into?eclipse):
?Help?-->?Install?New?Software...?
?Click?Add...?
?In?dialog?Add?Site?dialog,?click?Archive...?
?Navigate?to?install/src/gpd/jbpm-gpd-site.zip?and?click?'Open'?
?Clicking?OK?in?the?Add?Site?dialog?will?bring?you?back?to?the?dialog?'Install'?
?Select?the?jPDL?4?GPD?Update?Site?that?has?appeared?
?Click?Next...?and?then?Finish?
?Approve?the?license?
?Restart?eclipse?when?that?is?asked
查看是否成功安裝了插件:WindowàPreference中是否有Jboss?jBPM項。
2.4.?在Eclipse中添加jPDL4.4?Schema校驗
流程定義文件的xsd文件的路徑為:JBPM_HOME/src/jpdl-4.4.xsd。
添加到Eclipse中的方法為(jBPM4.4?User?Guide,?2.11.5.?Adding?jPDL?4?schema?to?the?catalog):
?Click?Window?-->?Preferences?
?Select?XML?-->?XML?Catalog?
?Click?'Add...'?
?The?'Add?XML?Catalog?Entry'?dialog?opens?
?Click?the?button?with?the?map-icon?next?to?location?and?select?'File?System...'?
?In?the?dialog?that?opens,?select?file?jpdl-4.4.xsd?in?the?src?directory?of?the?jBPM?installation?root.?
?Click?'Open'?and?close?all?the?dialogs
2.5.?準備jBPM4.4的開發環境
2.5.1.?添加jBPM4.4的jar包
1.?${JBPM_HOME}/jbpm.jar(核心包)
2.?JBPM_HOME/lib/*.jar,不添加以下jar包:servlet-api.jar,?junit.jar。其中junit.jar一定不要添加,因為是3.8.2版本,與我們使用的junit4有沖突。
3.?所使用的數據庫對應的驅動的jar包(第2步所添加的jar包中已包含mysql的jdbc驅動jar包)。
2.5.2.?添加并定制配置文件
1.?配置文件可以從JBPM_HOME/examples/src/中拷貝:
jbpm.cfg.xml、
logging.properties、
jbpm.hibernate.cfg.xml。
2.?修改logging.properties中的日志輸出級別為WARNING:?java.util.logging.ConsoleHandler.level=WARNING
3.?修改jbpm.hibernate.cfg.xml中的數據庫連接信息。如果使用MySql,使用的方言一定要是org.hibernate.dialect.MySQL5InnoDBDialect。
4.?數據庫連接編碼一定要是UTF-8。否則可能會在部署含有中文字符的流程定義時會拋異常,說sql語法錯誤。
說明:如果要改變jbpm.hibernate.cfg.xml的文件名稱,需要做:
1、從JBPM_HOME/src/中拷貝jbpm.tx.hibernate.cfg.xml放到工程的src/下,然后進行修改。
2、修改jbpm.tx.hibernate.cfg.xml中的hibernate主配置文件的路徑配置(指定的是相對于classpath的相對路徑)。
2.5.3.?初始化數據庫
1,?方法一:執行sql腳本文件${JBPM4.4_HOME}/install/src/db/create/jbpm.*.create.sql
2,?方法二:使用Hibernate的自動建表,在jbpm.hibernate.cfg.xml中配置:hibernate.hbm2ddl.auto=update。
3.?核心概念與相關API(Service?API)
3.1.?概念:Process?definition,?process?instance?,??execution
3.1.1.?Process?definition
ProcessDefinition,流程定義:
一個流程的步驟說明。如一個請假流程、報銷流程、借款流程等,是一個規則。
例:
3.1.2.?Process?instance
ProcessInstance,流程實例:
代表流程定義的一次執行。如張三昨天按請假流程請了一次假。一個流程實例包括了所有運行階段,?其中最典型的屬性就是跟蹤當前節點的指針。
3.1.3.?Execution
Execution,執行:
一般情況下,一個流程實例是一個執行樹的根節點。?
使用樹狀結構的原因在于,?這一概念只有一條執行路徑,?使用起來更簡單。?業務API不需要了解流程實例和執行之間功能的區別。?因此,?API里只有一個執行類型來引用流程實例和執行。
假設匯款和存檔可以同時執行,那么主流程實例就包含了2個用來跟蹤狀態的子節點:
4.1.?ProcessEngine與Service?API
4.1.1.?Configuration與ProcessEngine
Interacting?with?jBPM?occurs?through?services.?The?service?interfaces?can?be?obtained?from?the?ProcessEngine?which?is?build?from?a?Configuration.?A?ProcessEngine?is?thread?safe?and?can?be?stored?in?a?static?member?field.
使用默認的配置文件(jbpm.cfg.xml)生成Configuration并構建ProcessEngine:
ProcessEngine?processEngine?=?new?Configuration()
.buildProcessEngine();
或是使用如下代碼獲取使用默認配置文件的、單例的ProcessEngine對象:
ProcessEngine?processEngine?=?Configuration.getProcessEngine();
或是使用指定的配置文件(要放到classPath下):
ProcessEngine?processEngine?=?new?Configuration()
??????.setResource("my-own-configuration-file.xml")
??????.buildProcessEngine();
4.1.2.?jBPM?Service?API
jBPM所有的操作都是通過Service完成的,以下是獲取Service的方式:
RepositoryService?repositoryService?=?processEngine
.getRepositoryService();
ExecutionService?executionService?=?processEngine
.getExecutionService();
TaskService?taskService?=?processEngine
.getTaskService();
HistoryService?historyService?=?processEngine
.getHistoryService();
ManagementService?managementService?=?processEngine
.getManagementService();
各個Service的作用:
| RepositoryService | 管理流程定義 |
| ExecutionService | 管理執行的,包括啟動、推進、刪除Execution等操作 |
| TaskService | 管理任務的 |
| HistoryService | 歷史管理(執行完的數據管理,主要是查詢) |
| IdentityService | jBPM的用戶、組管理 |
| ManagementService |
4.1.3.?API風格
方法調用鏈
每一個方法都是流程有關的一個業務操作,默認是一個獨立的事務。
4.1.4.?查詢的有關API(風格)
| 功能說明 | 相應的查詢API |
| 查詢“流程定義” | ProcessDefinitionQuery?processDefinitionQuery?=? processEngine.getRepositoryService() .createProcessDefinitionQuery(); |
| 查詢“執行對象” (流程實例) | ProcessInstanceQuery?processInstanceQuery?=? processEngine.getExecutionService()?// .createProcessInstanceQuery(); |
| 查詢“任務” | TaskQuery?taskQuery?=?// processEngine.getTaskService()// .createTaskQuery(); |
| 查詢“執行歷史” (流程實例歷史) | HistoryProcessInstanceQuery?historyProcessInstanceQuery?=? processEngine.getHistoryService() .createHistoryProcessInstanceQuery(); |
| 查詢“任務歷史” | HistoryTaskQuery?historyTaskQuery?=? processEngine.getHistoryService() .createHistoryTaskQuery(); |
以上列出的Query對象有:
1.?ProcessDefinitionQuery
2.?ProcessInstanceQuery
3.?TaskQuery
4.?HistoryProcessInstanceQuery
5.?HistoryTaskQuery
這些Query對象的使用方法都是一致的,如下所示:
1,?添加過濾條件:調用其中的有關方法指定條件即可。如:
a)?processDefinitionQuery.processDefinitionKey("請假")是指定查詢key為”請假”的流程定義;
b)?taskQuery.assignee("張三")是指定辦理人為”張三”的任務。
2,?添加排序條件:
a)?調用?xxQuery.orderAsc(property),表示按某屬性升序排列
b)?調用?xxQuery.orderDesc(property),表示按某屬性降序排列
c)?可指定多個排序條件,就是代表第1順序,第2順序…等。
d)?屬性名在各自的Query對象(接口)中有常量定義,如:
i.?ProcessDefinitionQuery.PROPERTY_ID
ii.?ProcessDefinitionQuery.PROPERTY_KEY
iii.?TaskQuery.PROPERTY_NAME
iv.?TaskQuery.PROPERTY_ASSIGNEE
3,?指定分頁有關信息:
a)?調用方法xxQuery.page(firstResult,?maxResults);
b)?這是指定first與max的值(就是Hibernate中的Query.setFirstResult()與Query.setMaxResults())
c)?如果沒有調用這個方法,代表要查詢出符合條件的所有記錄。
4,?查詢得到結果:
a)?調用方法xxQuery.list();?表示查詢列表
b)?調用方法?xxQuery.uniqueResult();?表示查詢唯一的結果
c)?調用方法xxQuery.count();?表示查詢符合條件的記錄數量
5.?管理流程定義
沒有更新功能
5.1.?部署流程定義
注意區分Deployment與ProcessDefinition
5.1.1.?示例代碼1:流程定義有關文件在classpath中
String?deploymentId?=?processEngine.getRepositoryService()
.createDeployment()
.addResourceFromClasspath("process/test.jpdl.xml")
.addResourceFromClasspath("process/test.png")
.deploy();
5.1.2.?示例代碼2:一次添加多個流程定義有關文件(要先打成zip包)
String?deploymentId?=?processEngine.getRepositoryService()
.createDeployment()
.addResourcesFromZipInputStream(zipInputStream)
.deploy();
5.1.3.?說明
1,?.addResourceFromClasspath(resource);?可以調用多次以添加多個文件。文件重復添加也不會報錯。
2,?.addResourceFromInputStream(resourceName,?inputStream)添加一個文件(使用InputStream)
3,?.addResourcesFromZipInputStream(zipInputStream)添加多個文件,里面也可以有文件夾。
4,?以上方法可以在一起調用。
5.2.?刪除流程定義
5.2.1.?示例代碼1:刪除流程定義,如果有關聯的流程實例信息則報錯
repositoryService.deleteDeployment(deploymentId);
5.2.2.?示例代碼2:刪除流程定義,并刪除關聯的流程實例與歷史信息
repositoryService.deleteDeploymentCascade(deploymentId);
5.3.?查詢流程定義
5.3.1.?相關查詢API說明:ProcessDefinitionQuery
RepositoryService.createProcessDefinitionQuery()
5.3.2.?示例代碼1:查詢所有流程定義
//?1,構建查詢
ProcessDefinitionQuery?pdQuery?=?processEngine.getRepositoryService()?
.createProcessDefinitionQuery()//?
.orderAsc(ProcessDefinitionQuery.PROPERTY_NAME)//
.orderDesc(ProcessDefinitionQuery.PROPERTY_VERSION);
//?2,查詢出總數量與數據列表
long?count?=?pdQuery.count();
List<ProcessDefinition>?list?=?pdQuery.page(0,?100).list();//?分頁:取出前100條記錄
//?3,顯示結果
System.out.println(count);
for?(ProcessDefinition?pd?:?list)?{
System.out.println("id="?+?pd.getId()//
+?",deploymentId="?+?pd.getDeploymentId()//
+?",name="?+?pd.getName()//
+?",version="?+?pd.getVersion()//
+?",key="?+?pd.getKey());?//
}
5.3.3.?示例代碼2:查詢所有最新版本的流程定義列表
//?1,查詢,按version升序排序,則最大版本排在最后面
List<ProcessDefinition>?all?=?processEngine.getRepositoryService()//
.createProcessDefinitionQuery()//
.orderAsc(ProcessDefinitionQuery.PROPERTY_VERSION)
.list();
//?2,過濾出所有不同Key的最新版本(因為最大版本在最后面)
Map<String,?ProcessDefinition>?map?=?new?HashMap<String,?ProcessDefinition>();?//?map的key是流程定義的key,map的vlaue是流程定義對象
for?(ProcessDefinition?pd?:?all)?{
map.put(pd.getKey(),?pd);
}
Collection<ProcessDefinition>?result?=?map.values();
//?3,顯示結果
for?(ProcessDefinition?pd?:?result)?{
System.out.println("deploymentId="?+?pd.getDeploymentId()//?
+?",\t?id="?+?pd.getId()//?流程定義的id,格式:{key}-{version}
+?",\t?name="?+?pd.getName()
+?",\t?key="?+?pd.getKey()
+?",\t?version="?+?pd.getVersion());
}
5.4.?獲取部署對象中的文件資源內容
//?資源的名稱,就是?jbpm4_lob?表中的?NAME_?列表值
String?deploymentId?=?"90001";
String?resourceName?=?"test.png";?
InputStream?in?=?processEngine.getRepositoryService()
.getResourceAsStream(deploymentId,?resourceName);
5.5.?獲取流程圖中某活動的坐標
String?processDefinitionId?=?"test-1";?//?流程定義的id
String?activityName?=?"start1";?//?活動的名稱
ActivityCoordinates?c?=?processEngine.getRepositoryService()
.getActivityCoordinates(processDefinitionId,?activityName);
System.out.println("x="?+?c.getX()?
+?",y="?+?c.getY()?
+?",width="?+?c.getWidth()?
+?",height="?+?c.getHeight());
6.?執行流程實例
6.1.?啟動流程實例
說明:流程實例創建后,直接就到開始活動后的第一個活動,不會在開始活動停留。
6.1.1.?示例代碼1:使用指定key的最新版本的流程定義啟動流程實例
ProcessInstance?pi?=?processEngine.getExecutionService()
.startProcessInstanceByKey(processDefinitionKey);
6.1.2.?示例代碼2:使用指定key的最新版本的流程定義啟動流程實例,并設置一些流程變量
//?準備流程變量
Map<String,?Object>?variables?=?new?HashMap<String,?Object>();
variables.put("申請人",?"張三");
variables.put("報銷金額",?1000.00);
//?啟動流程實例,并設置一些流程變量
ProcessInstance?pi?=?processEngine.getExecutionService()
.startProcessInstanceByKey(processDefinitionKey,?variables);
6.2.?向后執行一步(Signal)
6.2.1.?示例代碼1:向后執行一步,使用唯一的outcome離開活動
processEngine.getExecutionService().signalExecutionById(executionId);
6.2.2.?示例代碼2:向后執行一步,使用唯一的outcome離開活動,并設置一些流程變量
Map<String,?Object>?variables?=?new?HashMap<String,?Object>();
variables.put("審批結果",?"同意");
processEngine.getExecutionService()
.signalExecutionById(executionId,?variables);
6.2.3.?示例代碼3:向后執行一步,使用指定的outcome離開活動
String?outcome=?"to?end1";
processEngine.getExecutionService()
.signalExecutionById(executionId,?outcome);
6.2.4.?示例代碼4:向后執行一步,使用指定的outcome離開活動,并設置一些流程變量
String?outcome=?"to?end1";
Map<String,?Object>?variables?=?new?HashMap<String,?Object>();
variables.put("審批結果",?"同意");
processEngine.getExecutionService()
.signalExecutionById(executionId,?outcome,?variables);
6.3.?查詢任務
6.3.1.?查詢個人任務列表
方式1:TaskService.findPersonalTasks(userId);
方式2:List<Task>?list?=?taskService.createTaskQuery()
.assignee(userId)
.list();
//?顯示任務信息
for?(Task?task?:?taskList)?{
System.out.println("id="?+?task.getId()//?任務的id
+?",name="?+?task.getName()//?任務的名稱
+?",assignee="?+?task.getAssignee()//?任務的辦理人
+?",createTime="?+?task.getCreateTime()?//?任務的創建(生成)的時間
+?",executionId="?+?task.getExecutionId());//?任務所屬流程實例的id
}
6.3.2.?查詢組任務列表
方式1:?taskService.findGroupTasks(userId);
方式2:?List<Task>?list?=?processEngine.getTaskService()//
.createTaskQuery()//
.candidate(userId)//
.list();
6.4.?完成任務
6.4.1.?正常完成任務(也可以同時設置一些流程變量)
String?taskId?=?"420001";
processEngine.getTaskService().completeTask(taskId);
processEngine.getTaskService().completeTask(taskId,?outcome);
processEngine.getTaskService().completeTask(taskId,?outcome,?variables);
6.4.2.?自行控制任務完成后是否可向后流轉
String?taskId?=?"420001";
//?1,設置為false代表:辦理完任務后不向后移動(默認為true)
TaskImpl?taskImpl?=?(TaskImpl)?processEngine
.getTaskService().getTask(taskId);
taskImpl.setSignalling(false);?
//?2,辦理完任務
processEngine.getTaskService().completeTask(taskId);
6.5.?拾取任務
1,?TaskService.takeTask(taskId,?userId),拾取組任務到個人任務列表中,如果任務有assignee,則會拋異常。
2,?processEngine.getTaskService().assignTask(taskId,?userId),轉交任務給其他人,(如果任務有assignee,則執行這個方法代表重新分配。也可以把assignee設為null表示組任務沒有人辦理了)
6.6.?設置與獲取流程變量
6.6.1.?設置流程變量
6.6.1.1.?方式1:根據?executionId?設置或獲取流程變量
ExecutionService.setVariable(executionId,?name,?value);
Object?obj?=?executionService.getVariable(executionId,?"請假人");
6.6.1.2.?方式2:根據?taskId?設置或獲取流程變量
TaskService.setVariables(taskId,?variables);?//?一次設置多個變量
Object?obj?=?executionService.getVariable(executionId,?"請假人");
6.6.1.3.?流程變量所支持的值的類型(jBPM?User?Guide,7.2.?Variable?types)
7.2.?Variable?types
jBPM?supports?following?Java?types?as?process?variables:
?java.lang.String?
?java.lang.Long?
?java.lang.Double?
?java.util.Date?
?java.lang.Boolean?
?java.lang.Character?
?java.lang.Byte?
?java.lang.Short?
?java.lang.Integer?
?java.lang.Float?
?byte[]?(byte?array)?
?char[]?(char?array)?
?hibernate?entity?with?a?long?id?
?hibernate?entity?with?a?string?id?
?serializable
For?persistence?of?these?variable,?the?type?of?the?variable?is?checked?in?the?order?of?this?list.?The?first?match?will?determine?how?the?variable?is?stored.?
6.7.?直接結束流程實例(自己手工結束)
String?processInstanceId?=?"test.10001";
processEngine.getExecutionService()
.endProcessInstance(processInstanceId,?ProcessInstance.STATE_ENDED);
7.?jBPM4.4的流程定義語言(設計流程)
7.1.?process(流程)
是.jpdl.xml的根元素,可以指定的屬性有:
| 屬性名 | 作用說明 |
| name | 流程定義的名稱,用于顯示。 |
| key | 流程定義的key,用于查詢。 如未指定,則默認為name的值。 |
| version | 版本,如果指定,則不能與已有的流程定義的版本重復;如未指定,則此key的流程定義的第1個為版本1,以后的是版本遞增(每次加1) |
7.2.?transition(連線、轉移)
1,?一個活動中可以指定一個或多個Transition(Start中只能有一個,End中沒有)。
a)?開始活動中只能有一個Transition。
b)?結束活動中沒有Transition。
c)?其他活動中有1條或多條Transition
2,?如果只有一個,則可以不指定名稱(名稱是null);如果有多個,則要分別指定唯一的名稱。
7.3.?流轉控制活動
7.3.1.?start(開始活動)
代表流程的開始邊界,一個流程有且只能有一個Start活動。開始活動只能指定一個Transition。在流程實例啟動后,會自動的使用這個唯一的Transition離開開始活動,到一下個活動。
7.3.2.?end、end-error、end-cancel(結束活動)
代表流程的結束邊界,可以有多個,也可以沒有。如果有多個,則到達任一個結束活動,整個流程就都結束了;如果沒有,則到達最后那個沒有Transition的活動,流程就結束了。
7.3.3.?state(狀態活動)
功能:等待。
7.3.4.?task(任務活動)
分配任務:
1,?actor=#{String型的變量}
2,?AssignmentHandler,需要在<task>元素中寫<assignment-handler?class="AssignmentHandlerImpl"/>子元素。
a)?指定的類要實現AssignmentHandler接口
b)?在其中可以使用Assignable.setAssignee(String),分配個人任務。
7.3.5.?decision(判斷活動)
1,使用expression,如:expr="#{'to?state2'}"
2,使用Handler,要實現DecisionHandler接口
3,如果同時配置了expression與Handler,則expression有效,忽略Handler。
7.3.6.?fork、join(分支/聚合活動)
這是多個分支并行(同時)執行的,并且所有的分支Execution都到Join活動后才離向后執行。
7.4.?自定義活動(Custom)
1,在<custom>元素中指定class屬性為指定的類。
2,這個類要實現ExternalActivityBehaviour接口,其中有兩個方法:
1,execute(ActivityExecution),節點的功能代碼
2,signal(ActivityExecution,?String,?Map),在當前節點等待時,外部發信號時的行為
3,在execute()方法中,可以調用以下方法對流程進行控制
1,ActivityExecution.waitForSignal(),在當前節點等待。
2,ActivityExecution.takeDefaultTransition(),使用默認的Transition離開,當前節點中定義的第一個為默認的。
3,ActivityExecution.take(String?transitionName),使用指定的Transition離開
4,ActivityExecution.end(),結束流程實例
4,也可以實現ActivityBehaviour接口,只有一個方法execute(ActivityExecution),這樣就不能等待,否則signal時會有類轉換異常。
7.5.?事件
1,?在根元素中,或在節點元素中,使用<on?event="">元素指定事件,其中event屬性代表事件的類型。
2,?在<on>中用子元素<event-listener?class="EventListenerImpl"?/>,指定處理的類,要求指定的類要實現EventListener接口
3,? 事件類型:
a)?<on>元素放在根元素(<process>)中,可以指定event為start或end,表示流程的開始與結束。
b)?<on>元素放在節點元素中,可以指定event為start或end,表示節點的進入與離開
c)?在Start節點中只有end事件,在End節點中只有start事件。
d)?在<transition>元素中直接寫<event-listener?class="">,就是配置事件。(因為在這里只有一個事件,所以不用寫on與類型)
e)?在<task>元素中還可以配置assign事件,是在分配任務時觸發的。
8.?jBPM4.4應用
8.1.?與Spring集成(jBPM4.4?Developers?Guide,?Chapter?17.?Spring?Integration)
8.1.1.?在jbpm.cfg.xml中
1,刪除配置:<import?resource="jbpm.tx.hibernate.cfg.xml"?/>
2,增加配置:<import?resource="jbpm.tx.spring.cfg.xml"?/>
8.1.2.?在applicationContext.xml中配置
<!--?配置ProcessEngine(整合jBPM4)?-->
<!--?jbpmCfg是相對于classpath的相對路徑,默認值為jbpm.cfg.xml?-->
<bean?id="springHelper"?
class="org.jbpm.pvm.internal.processengine.SpringHelper">
<property?name="jbpmCfg"?value="jbpm.cfg.xml"></property>
</bean>
<bean?id="processEngine"?factory-bean="springHelper"?
factory-method="createProcessEngine"?/>
8.1.3.?測試
@Test?//?測試ProcessEngine
public?void?testProcessEngine()?{
ProcessEngine?processEngine?=?(ProcessEngine)ac.getBean("processEngine");
Assert.assertNotNull(processEngine);
}
8.1.4.?注意事項
如果做了JBPM4.4與Spring整合(使用了jbpm.tx.spring.cfg.xml),則在程序中就一定要使用Spring注入ProcessEngine,千萬不能使用Configuration.getProcessEngine()生成ProcessEngine,因為這時內部的代碼有以下邏輯:如果整合了Spring但沒有ApplicationContext,就默認讀取applicationContext.xml創建ApplicationContext實例并從中獲取名為”ProcessEngine”的對象。而這時如果把pe?=?Configuration.getProcessEngine()寫成某Spring中管理的bean的初始化代碼,就會有無限循環,不停的創建ApplicationContext了!
8.2.?自行控制事務
1,?修改?jbpm.tx.hibernate.cfg.xml
a)?不讓jBPM自行管理事務:去掉<standard-transaction-interceptor?/>
b)?讓Jbpm使用SessionFactory.getCurrentSession():修改為?<hibernate-session?current="true"?/>
2,?配置可以使用SessionFactory.getCurrentSession(),在jbpm.hibernate.cfg.xml?中配置:<property?name="hibernate.current_session_context_class">thread</property>
3,?要使用同一個SessionFactory,且都要使用?SessionFactory.getCurrentSession()?獲取?Session:
a)?同一個SessionFactory:SessionFactory?sf?=?processEngine.get(SessionFactory.class)
b)?在?BaseDaoImpl?中增加:
i.?getSession()?{?return?HibernateUtils.getSessionFactory().getCurrentSession();?}
ii.?getProcessEngine(){?return?org.jbpm.api.Configuration.getProcessEngine();?}
4,?統一的打開與提交或回滾事務:使用?OpenSessionInViewFilter?控制事務。
8.3.?啟動Tomcat后,訪問JSP時(使用的是MyEclipse自帶的Tomcat,是6.0的版本),報錯:???Caused?by:?java.lang.LinkageError:?loader?constraints?violated?when?linking?javax/el/ExpressionFactory?class
at?org.apache.jsp.WEB_002dINF.jsp.UserAction.loginUI_jsp._jspInit(loginUI_jsp.java:39)
at?org.apache.jasper.runtime.HttpJspBase.init(HttpJspBase.java:52)
at?org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:159)
at?org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:329)
at?org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)
at?org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
...?40?more
說明:原因是Jbpm的juel.jar,?juel-engine.jar,?juel-impl.jar包和Tomcat6.0中的el-api.jar包沖突了。
有三個解決辦法:
1,方法一:在MyEclipse的Preferences?->?MyEclipse?->?Application?Servers?->?Tomcat?->?..?->?Paths?中配置?Append?to?classpath,選中?juel.jar,?juel-engine.jar,?juel-impl.jar?這三個jar包就可以了。
2,方法二:將?juel.jar,?juel-engine.jar,?juel-impl.jar?這三個包復制到tomcat6下?lib/?中,并刪除原來的el-api.jar,
切記還要把工程中?WEB-INF\lib?下的?juel.jar,?juel-engine.jar,?juel-impl.jar?刪除,不然還是要沖突。
3,方法三:換成tomcat5.5,就沒有問題了。
8.4.?完成流程實例中的最后一個任務時報錯(任務實例結束時),或刪除流程定義級聯刪除流程實例時,報錯如下:
com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException:?Cannot?delete?or?update?a?parent?row:?a?foreign?key?constraint?fails?(`itcastoa_20100909/jbpm4_execution`,?CONSTRAINT?`FK_EXEC_INSTANCE`?FOREIGN?KEY?(`INSTANCE_`)?REFERENCES?`jbpm4_execution`?(`DBID_`))
解決辦法:把方言設為?MySQL5InnoDBDialect,不能是?MySQLDialect。
總結
以上是生活随笔為你收集整理的jbpm_工作流框架笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么中央空调的能耗比较低?
- 下一篇: Hibernate延迟加载