【代碼篇】JBPM4.4開發流程節點(動態代理實現流程管理業務)
來源:程序員人生 發布時間:2015-03-04 08:12:38 閱讀次數:3282次
繼之前的博客,【思想篇】工作流技術JBPM4.4開發入門(4),【思想篇】工作流技術JBPM4.4開發入門(5)本篇博客來結合代碼簡單說說,如何讓流程來管理業務:
先來看看我們抽出來的代理類:
StartAbstractJBPM:流程啟動節點
package com.hjy.ssh.action;
import com.hjy.ssh.beans.AbstractApply;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.annotation.Resource;
import org.jbpm.api.ProcessInstance;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import java.lang.reflect.InvocationHandler;
import java.util.Map;
import com.hjy.ssh.service.JBPMService;
import com.opensymphony.xwork2.ActionSupport;
@Controller
@Scope("prototype")
public class StartAbstractJBPM extends ActionSupport {
private static final long serialVersionUID = 1L;
//定義1個屬性變量
private Map<String, Object> variablesMap;
private String pdKey;
protected JBPMService jbpmService;
public void common(String pdKey,Map<String, Object> variablesMap,JBPMService jbpmService){
this.variablesMap=variablesMap;
this.pdKey=pdKey;
this.jbpmService=jbpmService;
}
//想嘗試能否根據其他方式傳參,new的話太耗費資源
/*public StartAbstractJBPM(String pdKey,Map<String, Object> variablesMap,JBPMService jbpmService){
this.variablesMap=variablesMap;
this.pdKey=pdKey;
this.jbpmService=jbpmService;
}*/
//動態代理類只能代理接口(不支持抽象類),代理類都需要實現InvocationHandler類,實現invoke方法。該invoke方法就是調用被代理接口的所有方法時需要調用的,該invoke方法返回的值是被代理接口的1個實現類
public class LogHandler1 implements InvocationHandler{
// 目標對象
private Object targetObject;
//綁定關系,也就是關聯到哪一個接口(與具體的實現類綁定)的哪些方法將被調用時,履行invoke方法。
public Object newProxyInstanceStart(Object targetObject){
this.targetObject=targetObject;
//該方法用于為指定類裝載器、1組接口及調用途理器生成動態代理類實例
//第1個參數指定產生代理對象的類加載器,需要將其指定為和目標對象同1個類加載器
//第2個參數要實現和目標對象1樣的接口,所以只需要拿到目標對象的實現接口
//第3個參數表明這些被攔截的方法在被攔截時需要履行哪一個InvocationHandler的invoke方法
//根據傳入的目標返回1個代理對象
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
@Override
//關聯的這個實現類的方法被調用時將被履行
// InvocationHandler接口的方法,proxy表示代理,method表示原對象被調用的方法,args表示方法的參數
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("start-->>");
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
Object ret=null;
try{
//原對象方法調用前處理日志信息
System.out.println("satrt-->>");
//啟動流程
ProcessInstance pi=(ProcessInstance) jbpmService.startProcessInstanceByKey(pdKey,variablesMap);
//調用目標方法
AbstractApply abstractApply=(AbstractApply)args[0];
abstractApply.setExecuteId(pi.getId());
args[0]=abstractApply;
ret=method.invoke(targetObject, args);
//調用完成當前結點
// >> 辦理完第1個任務“提交申請”
jbpmService.completeFirstTask(pi);
//原對象方法調用后處理日志信息
System.out.println("success-->>");
}catch(Exception e){
e.printStackTrace();
System.out.println("error-->>");
throw e;
}
return ret;
}
}
}
HandleAbstractJBPMAction:任務辦理節點
package com.hjy.ssh.action;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.annotation.Resource;
import org.jbpm.api.ProcessInstance;
import java.lang.reflect.InvocationHandler;
import com.hjy.ssh.service.JBPMService;
public abstract class HandleAbstractJBPMAction<T> extends ModelDrivenBaseAction<T> {
protected String outcome;//分支
protected String taskId;//任務id
protected boolean approval;//是不是同意
@Resource
protected JBPMService jbpmService;
//動態代理類只能代理接口(不支持抽象類),代理類都需要實現InvocationHandler類,實現invoke方法。該invoke方法就是調用被代理接口的所有方法時需要調用的,該invoke方法返回的值是被代理接口的1個實現類
public class LogHandler implements InvocationHandler{
// 目標對象
private Object targetObject;
//綁定關系,也就是關聯到哪一個接口(與具體的實現類綁定)的哪些方法將被調用時,履行invoke方法。
public Object newProxyInstance(Object targetObject){
this.targetObject=targetObject;
//該方法用于為指定類裝載器、1組接口及調用途理器生成動態代理類實例
//第1個參數指定產生代理對象的類加載器,需要將其指定為和目標對象同1個類加載器
//第2個參數要實現和目標對象1樣的接口,所以只需要拿到目標對象的實現接口
//第3個參數表明這些被攔截的方法在被攔截時需要履行哪一個InvocationHandler的invoke方法
//根據傳入的目標返回1個代理對象
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
@Override
//關聯的這個實現類的方法被調用時將被履行
// InvocationHandler接口的方法,proxy表示代理,method表示原對象被調用的方法,args表示方法的參數
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("start-->>");
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
Object ret=null;
try{
//原對象方法調用前處理日志信息
System.out.println("satrt-->>");
//保存處理信息
//abstractApprove();
// 2,辦應當前任務,調用完成當前結點
ProcessInstance pi=jbpmService.completeTask(taskId, outcome);
//調用工作流的操作
if(approval==false){
if (pi != null) { // 如果流程還未結束
//結束當前流程
jbpmService.endProcessInstance(pi);
}
}
//調用目標方法
ret=method.invoke(targetObject, args);
//調用工作流,每一個都實現這么1個接口就能夠,判斷是不是要修改
isEnd(pi);
//原對象方法調用后處理日志信息
System.out.println("success-->>");
}catch(Exception e){
e.printStackTrace();
System.out.println("error-->>");
throw e;
}
return ret;
}
}
// 抽象方法,實現保存處理信息,和設置同意不同意,但不需要更新
protected abstract void abstractApprove()throws Exception;
// 抽象方法,如果為最后的結點且同意了,那末需要更新的數據表
protected abstract void isEnd(ProcessInstance pi);
//-----------
public String getOutcome() {
return outcome;
}
public void setOutcome(String outcome) {
this.outcome = outcome;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public boolean isApproval() {
return approval;
}
public void setApproval(boolean approval) {
this.approval = approval;
}
}
注:以上的代理使用了兩種方式傳值,由于java不支持多重繼承,故第1種方式更好些,但是第2種方式傳值更加簡單,大家根據需要來選擇便可!
以上這兩個是抽象出來的代理類,那末它起到了甚么作用呢?
下面我們來1起看看它們的利用:
對應啟動節點:
/** 提交申請 ,啟開工作流--想成是宿主程序*/
public String edit() throws Exception {
Long stuCourseId=model.getId();
//提交申請
//封裝申請信息,學生的申請信息
StuCourseApply stuCourseApply = new StuCourseApply();
stuCourseApply.setStuCourseId(stuCourseId);
newCourse=new String(newCourse.getBytes("iso⑻859⑴"),"utf⑻");
newTeacher=new String(newTeacher.getBytes("iso⑻859⑴"),"utf⑻");
stuCourseApply.setApplicant(getCurrentUser()); // 申請人,當前用戶
stuCourseApply.setOldCourse(model.getCourse());
stuCourseApply.setNewCourse(newCourse);
stuCourseApply.setNewTeacher(newTeacher);
stuCourseApply.setOldTeacher(model.getTeacher());
stuCourseApply.setTitle("修改課程信息");
String processDefinitionKeyStr=new String(processDefinitionKey.getBytes("iso⑻859⑴"),"utf⑻");
stuCourseApply.setProcessDefinitionKey(processDefinitionKeyStr);
// 調用業務方法(保存申請信息)
// 1,設置屬性并保存stuCourseApply
stuCourseApply.setApplyTime(sdf.format(new Date())); // 申請時間,當前時間
stuCourseApply.setStatus(StuCourseApply.STATUS_RUNNING);
//兩次保存?
stuCourseApplyService.save(stuCourseApply);
// 2, 準備流程變量
Map<String, Object> variablesMap = new HashMap<String, Object>();
variablesMap.put("stuCourseApply", stuCourseApply);
//獲得流程定義的key
String pdKey = stuCourseApply.getProcessDefinitionKey();
// 3,啟動流程實例開始流轉,并帶上流程變量(當前的申請信息),調用宿主程序
// 調用業務,保存申請信息
startAbstractJBPM.common(pdKey, variablesMap, jbpmService);
StartAbstractJBPM.LogHandler1 logHandler = startAbstractJBPM.new LogHandler1();
//放到代理中設置值了
//stuCourseApply.setExecuteId(pi.getId());
StuCourseApplyService stuCourseApplyService1=(StuCourseApplyService)logHandler.newProxyInstanceStart(stuCourseApplyService);
stuCourseApplyService1.save(stuCourseApply);
return "toStuApplicationList"; // 成功后轉到"我的申請查詢"
}
對應辦理節點:
/** 審批處理 */
public String approve() throws Exception {
abstractApprove();
// 利用代理
LogHandler logHandler=new LogHandler();
// 調用業務,更新狀態,更新狀態之前會先調用工作流的完成當前任務方法
StuCourseApplyService stuCourseApplyService1=(StuCourseApplyService)logHandler.newProxyInstance(stuCourseApplyService);
stuCourseApplyService1.update(stuCourseApply);
return "toStuTaskList"; // 成功后轉到待我審批頁面
}
通過這兩段代碼,相信大家可以看出在這兩段代碼中已不存在工作流的任何內容,而此時我們的流程卻仍然被工作流來管理著,也就是我們將所有有關工作流的方法均抽象出來,讓我們的類單純的應對業務,在調用業務的方法時我們調用代理,而此時的代理中已將工作流的啟動辦理等1系列操作封裝進去,在我們調用代理方法時已啟動了工作流,再處理時也操作了工作流的辦理,故全部業務流程在我們無需了解工作流的情況下就已實現了被流程管理。
我們1直在說AOP,那末甚么是AOP?
AOP(AspectOrientedProgramming):將日志記錄,性能統計,安全控制,事務處理,異常處理等代碼從業務邏輯代碼中劃分出來,通過對這些行動的分離,我們希望可以將它們獨立到非指點業務邏輯的方法中,進而改變這些行動的時候不影響業務邏輯的代碼---兩個字概括:解耦。
總結:
最想說的1句話:會者不難,難者不會。在學習工作流的這段期間,各種的不理解,各種的質疑自己,這個是AOP嗎?這樣做是我們想要的嗎?有時候仍會問自己甚么是工作流,說到底它到底給我們帶來了甚么好處?
工作流(Workflow),就是“業務進程的部份或整體在計算機利用環境下的自動化”,它主要解決的是“使在多個參與者之間依照某種預定義的規則自動進行傳遞文檔、信息或任務的進程,從而實現某個預期的業務目標,或促使此目標的實現”這段話說的真的很棒,但是我覺得我們要做到的不單單是這些,要補充的1點就是實現工作流的AOP!
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈