【代码篇】JBPM4.4开发流程节点(动态代理实现流程管理业务)

继之前的博客,【思想篇】工作流技术JBPM4.4开发入门(四)【思想篇】工作流技术JBPM4.4开发入门(五)本篇博客来结合代码简单说说,如何让流程来管理业务:

先来看看我们抽出来的代理类:

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;

		//定义一个属性变量
		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方法返回的值是被代理接口的一个实现类
		public class LogHandler1 implements InvocationHandler{
	    // 目标对象
	    private Object targetObject;
	    //绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
	    public Object newProxyInstanceStart(Object targetObject){
	        this.targetObject=targetObject;
	        //该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
	        //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
	        //第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
	        //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
	        //根据传入的目标返回一个代理对象
	        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方法返回的值是被代理接口的一个实现类
	public class LogHandler implements InvocationHandler{
	    // 目标对象
	    private Object targetObject;
	    //绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
	    public Object newProxyInstance(Object targetObject){
	        this.targetObject=targetObject;
	        //该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
	        //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
	        //第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
	        //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
	        //根据传入的目标返回一个代理对象
	        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);  

	            //调用工作流,每个都实现这么一个接口就可以,判断是否要修改
	            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不支持多重继承,故第一种方式更好些,但是第二种方式传值更加简单,大家根据需要来选择即可!

以上这两个是抽象出来的代理类,那么它起到了什么作用呢?

下面我们来一起看看它们的应用:

对应启动节点:

	/** 提交申请 ,启动工作流--想成是宿主程序*/
	public String edit() throws Exception {

		Long stuCourseId=model.getId();
		//提交申请
		//封装申请信息,学生的申请信息
		StuCourseApply stuCourseApply = new StuCourseApply();
		stuCourseApply.setStuCourseId(stuCourseId);
		newCourse=new String(newCourse.getBytes("iso-8859-1"),"utf-8");
		newTeacher=new String(newTeacher.getBytes("iso-8859-1"),"utf-8");
		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-8859-1"),"utf-8");
	 	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"; // 成功后转到待我审批页面
}

通过这两段代码,相信大家可以看出在这两段代码中已经不存在工作流的任何内容,而此时我们的流程却依然被工作流来管理着,也就是我们将所有有关工作流的方法均抽象出来,让我们的类单纯的应对业务,在调用业务的方法时我们调用代理,而此时的代理中已经将工作流的启动办理等一系列操作封装进去,在我们调用代理方法时已经启动了工作流,再处理时也操作了工作流的办理,故整个业务流程在我们无需了解工作流的情况下就已经实现了被流程管理。

我们一直在说AOP,那么什么是AOP?

AOP(AspectOrientedProgramming):将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码---两个字概括:解耦。

总结:

最想说的一句话:会者不难,难者不会。在学习工作流的这段期间,各种的不理解,各种的质疑自己,这个是AOP吗?这样做是我们想要的吗?有时候仍会问自己什么是工作流,说到底它到底给我们带来了什么好处?

工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此目标的实现”这段话说的真的很棒,但是我觉得我们要做到的不仅仅是这些,要补充的一点就是实现工作流的AOP!

时间: 2024-11-08 17:30:51

【代码篇】JBPM4.4开发流程节点(动态代理实现流程管理业务)的相关文章

Mybatis框架三:DAO层开发、Mapper动态代理开发

这里是最基本的搭建:http://www.cnblogs.com/xuyiqing/p/8600888.html 接下来做到了简单的增删改查:http://www.cnblogs.com/xuyiqing/p/8601506.html 但是发现代码重复过多等问题 接下来整合并实现DAO开发: 一:原始DAO开发: package dao; import pojo.User; public interface UserDao { public User selectUserById(Integer

MyBatis开发Dao的原始Dao开发和Mapper动态代理开发

摘自:https://www.cnblogs.com/yichunguo/p/11990961.html 目录 咳咳...初学者看文字(Mapper接口开发四个规范)属实有点费劲,博主我就废了点劲做了如下图,方便理解: 原始Dao开发方式 1. 编写映射文件 3.编写Dao实现类 4.编写Dao测试 Mapper动态代理方式 1.定义Mapper.xml(映射文件) 2.编写UserMapper.xml配置文件内容: 3.编写UserMapper(接口文件) 4.加载UserMapper.xml

mybatis(Mybatis与hibernate的不同、原始Dao开发、Mapper动态代理开发)

1.Mybatis与hibernate的不同 (1)Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句.mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象. mybatis需要在配置文件中书写sql语句: <delete id="deleteStudentById" parameterType="

java基础第十八篇之单元测试、注解和动态代理

1:单元测试 1)JUnit是一个Java语言的单元测试框架,这里的单元指的就是方法 2)单元测试用来替换以前的main方法 1.1 Junit测试的步骤 1:在方法的上面加上 @Test 2:将junit库添加到工程的构建路径 3:选中方法--->右键--->JunitTest 1.2 常用的Junit测试注解 常用注解 @Test,用于修饰需要执行的方法 @Before,测试方法前执行的方法 @After,测试方法后执行的方法 1.3 测试有返回值的方法 public int sum(in

你真的完全了解Java动态代理吗?看这篇就够了

之前讲了<零基础带你看Spring源码--IOC控制反转>,本来打算下一篇讲讲Srping的AOP的,但是其中会涉及到Java的动态代理,所以先单独一篇来了解下Java的动态代理到底是什么,Java是怎么实现它的. 动态代理看起来好像是个什么高大上的名词,但其实并没有那么复杂,直接从字面就很容易理解.动态地代理,可以猜测一下它的含义,在运行时动态地对某些东西代理,代理它做了其他事情.先不去搞清楚这个动态代理真正的含义,我们来举个生动的例子来理解下它到底做了什么. 一个例子 一个程序员Devel

java开发必学知识:动态代理

目录 1. 引言 2. 代理模式及静态代理 2.1 代理模式说明 2.2 静态代理 2.3 静态代理局限性 3. 动态代理 3.1 JAVA反射机制 3.2 JDK动态代理 3.2.1 JDK动态代理 3.2.2 JDK动态代理与限制 3.4 CGLIB动态代理 4. 动态代理在Spring的应用:AOP 4.1 AOP 概念 4.2 AOP编程 4.2.1 引入aop依赖 4.2.2 定义切面.切点与通知 5. 总结 参考资料 往期文章 一句话概括:java动态代理通过反射机制,可在不修改原代

理解java动态代理

java动态代理是java语言的一项高级特性.在平时的项目开发中,可能很难遇到动态代理的案例.但是动态代理在很多框架中起着不可替代的作用,例如Spring的AOP.今天我们就聊一聊java动态代理的实现原理. jdk对于动态代理的支持主要依赖于两个类:Proxy和InvocationHandler.我们先看一下类图. Subject类是主题类,定义了我要做什么.我们需要代理的类即实现Subject接口的RealSubject. 1.InvocationHandler InvocationHand

JDK动态代理

一.基本概念 1.什么是代理? 在阐述JDK动态代理之前,我们很有必要先来弄明白代理的概念.代理这个词本身并不是计算机专用术语,它是生活中一个常用的概念.这里引用维基百科上的一句话对代理进行定义: A proxy is an agent or substitute authorized to act for another person or a document which authorizes the agent so to act. 意思是说:代理指的是一个代理人(或替代品),它被授权代表

Java核心技术点之动态代理

本篇博文会从代理的概念出发,介绍Java中动态代理技术的使用,并进一步探索它的实现原理.由于个人水平有限,叙述中难免出现不清晰或是不准确的地方,希望大家可以指正,谢谢大家:) 一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,“委托者”对我们来说是不可见的:其次,微商代理主要以朋友圈的人为目标客户,这就相当于为厂家做了一次对客户群体的“过滤”.我们把微商代理