基于Spring的轻量级工作流框架
项目地址
- 码云:https://git.oschina.net/null_584_3382/business-flow-parent
- github:https://github.com/Athlizo/business-flow-parent
先通俗的介绍一下框架
该框架的灵感来自于现实中的公交系统。公交系统的中最重要的几个元素,及其对工作流框架的对应:
- 乘客:对应工作流框架的中的数据(data)
- 公交车:数据的载体,
- 车站:一个车站可以看成工作流中的一个节点,负责处理“公交车”上的“乘客”。
- 线路:由哪些节点组成一个完整的工作流的处理链
是不是感觉整个公交系统就是一个庞大的工作流处理网,每时每刻都公交车从车站出发,到达一个车站,上下乘客又开往下一个车站(当然前提是不出事故(exception))。
框架中的一些重要接口
BusContext
保存一个业务处理逻辑的上下文环境。
Bus
一个Bus是保存一次业务流程的上下文环境,业务的起始节点、抛异常的时候怎么处理等等。一个业务流都会新建一个bus,让后顺着一个一个节点进行处理。
Station
Station为一个业务流(处理链)中的一个单独的节点。这个节点应该是只依赖于Bus中的上下文环境,根据bus的上下文环境进行处理,并且把处理后的结果(如果有)也放入bus的上下文环境中,供下游的节点使用。 例如下面就是一个Station,从Bus上下文中获取maxValue和minValue,如果之间的差小于10则设置路由的key为OK(Routing根据这个进行路由)
Routing
由于Station之间并没有直接关联,因此Routing负责连接各个Station,每个Station都有一个Routing来负责处理bus到底哪个Station,即可以动态的决定Bus的下一个Station
如何使用
举例子
Station
一个Station就是一个Spring容器管理的Bean(实现了com.lizo.busflow.station.Station接口)。一个station应该是独立的,有一定通用性的业务处理类,例如一个参数检查器,ip控制或一个相对对立的业务逻辑等等。
public class GetDiff implements Station {
public void abstractCalculate(@BusParameter("maxValue") int a, @BusParameter("minValue") int b, Bus bus) {
if (Math.abs(a - b) < 10) {
bus.setRoutingKey("ok");
} else {
bus.setRoutingKey("no");
}
}
@Override
public String getName() {
return null;
}
}
Routing
Routing的一定是要一个对应的Station的,例如可以在xml配置中,根据路由的key为进行选择下一个处理的Station
<!--这个是一个Station-->
<bean id="getDiff" class="com.lizo.demo.station.GetDiff"></bean> <!--这个是一个Routing,包含了对应的Station Bean-->
<bf:stop id="getDiffStop" ref="getDiff" method="abstractCalculate">
<bf:routing value="ok" to="soutOutOkStop"/>
<bf:routing value="no" to="soutOutNoStop"/>
</bf:stop>
注意,
- 后面所说的Station默认是指包含了Routing的Bean(<bf:stop>标签),并不是Station那个Bean
- 需要ref制定一个Spring bean,使用method制定是由那个method来处理。
- 默认会使用BusContext的key对应方法的参数名来自动注入,如果有特殊需要,可以使用@BusParameter注解,指定BusContext对应的key,是否是必须(默认是必须的,设置为非必须,会注入默认值)。
Bus
一个完整Bus在xml中定义,如下:
<bf:bus id="testBus" start="findMaxStop" maxPath="1000" exception="exceptionStation" finish="endStation" class="xxx.xxx.xxx.myBus"/>
其中:
- id: 对应的一个Spring Bean的name
- start: 对应工作流开始Routing
- maxPath:规定了bus如果处理的次数大于这个数就会跑出异常(防止死循环)
- exception:指定当发送异常的时候由哪个Station进行处理,例如一个打错误日志的Station
- finish:表示当整个流程处理完以后会由哪个Station最最后处理
- class:制定bus的类型,如果为空就使用默认的com.lizo.busflow.bus.DefaultBus
看个DEMO
现在有一个业务需求,需要做以下处理
- 输入一个整型的list
- 找出最大值和最小值
- 如果最大值和最小值的差大于10输出“no”,否则输入“ok” 、 当然真实项目中的业务流程不会这么简单,只是这里使用这个做个例子
第一步 编写独立的Station
<bean id="findMax" class="com.lizo.demo.station.FindMax"/>
<bean id="findMin" class="com.lizo.demo.station.FindMin"/>
<bean id="soutOutOk" class="com.lizo.demo.station.SoutOutOk"/>
<bean id="soutOutNo" class="com.lizo.demo.station.SoutOutNo"/>
<bean id="getDiff" class="com.lizo.demo.station.GetDiff">
例如getDiff的核心代码如下:
public class GetDiff implements Station {
public void abstractCalculate(@BusParameter("maxValue") int a, @BusParameter("minValue") int b, BusContext busContext) {
if (Math.abs(a - b) < 10) {
busContext.setRoutingKey("ok");
} else {
busContext.setRoutingKey("no");
}
}
@Override
public String getName() {
return null;
}
}
把他们串起来吧
<bf:stop id="findMaxStop" ref="findMax" method="doBusiness">
<bf:routing to="findMinStop"/>
</bf:stop> <bf:stop id="findMinStop" ref="findMin" method="doBusiness">
<bf:routing to="getDiffStop"/>
</bf:stop> <bf:stop id="getDiffStop" ref="getDiff" method="abstractCalculate">
<bf:routing value="ok" to="soutOutOkStop"/>
<bf:routing value="no" to="soutOutNoStop"/>
</bf:stop> <bf:stop id="soutOutOkStop" ref="soutOutOk" method="printOk"/> <bf:stopid="soutOutNoStop"ref="soutOutNo"method="printNo"/>
创建一个bus,开车吧司机
<bf:bus id="testBus" start="findMaxStop" />
运行demo
public class DemoApplication {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:bus-config.xml");
Bus testBus = BusFactory.createNewBus("testBus");
List<Integer> input = Arrays.asList(5, 7, 1, 0, 1, 3, 4, 5, 6, 4);
testBus.putContext("intList", input);
testBus.run();
testBus = BusFactory.createNewBus("testBus");
input = Arrays.asList(52, 7, 1, -10, 1, 3, 4, 5, 6, 4);
testBus.putContext("intList", input);
testBus.run();
}
}
基于Spring的轻量级工作流框架的更多相关文章
- Fastflow——基于golang的轻量级工作流框架
Fastflow 是什么?用一句话来定义它:一个 基于golang协程.支持水平扩容的分布式高性能工作流框架. 它具有以下特点: 易用性:工作流模型基于 DAG 来定义,同时还提供开箱即用的 API, ...
- 分享自己写的基于Dapper的轻量级ORM框架~
1.说明 本项目是一个使用.NET Standard 2.0开发的,基于 Dapper 的轻量级 ORM 框架,包含基本的CRUD以及根据表达式进行一些操作的方法,目前只针对单表,不包含多表连接操作. ...
- 基于spring的quartz定时框架,实现简单的定时任务功能
在项目中,经常会用到定时任务,这就需要使用quartz框架去进行操作. 今天就把我最近做的个人主页项目里面的定时刷新功能分享一下,很简单. 首先需要配置一个配置文件,因为我是基于spring框架的,所 ...
- 史上最轻松入门之Spring Batch - 轻量级批处理框架实践
从 MariaDB 一张表内读 10 万条记录,经处理后写到 MongoDB . Batch 任务模型 具体实现 1.新建 Spring Boot 应用,依赖如下: <!-- Web 应用 -- ...
- 自己编写基于MVC的轻量级PHP框架
做WEB开发已有三年,每次都写重复的东西, 因此,想自己写一下框架,以后开发方便.本人之前asp.NET一年开发,jsp半年,可是后来因为工作的原故换成PHP.其实很不喜欢PHP的语法.还有PHP的函 ...
- jpbm工作流框架
一:JBPM是什么?有什么用?能解决什么问题? 现实生活中有很多需要走一些流程的过程,比如请假流程,报销流程等,使用工作流框架,即可写一个流程即可,添加流程时不在繁琐的建立新的各种配置. 1:jBPM ...
- 微博轻量级RPC框架Motan
Motan 是微博技术团队研发的基于 Java 的轻量级 RPC 框架,已在微博内部大规模应用多年,每天稳定支撑微博上亿次的内部调用.Motan 基于微博的高并发和高负载场景优化,成为一套简单.易用. ...
- 微博轻量级RPC框架Motan正式开源:支撑千亿调用
支撑微博千亿调用的轻量级 RPC 框架 Motan 正式开源了,项目地址为https://github.com/weibocom/motan. 微博轻量级RPC框架Motan正式开源 Motan 是微 ...
- C# 的轻量级 RPC 框架
Redola.Rpc 的一个小目标 Redola.Rpc 的一个小目标 Redola.Rpc 的一个小目标:20000 tps. Concurrency level: 8 threads Comple ...
随机推荐
- 【学习笔记】TCP通信的细节及TCP连接对HTTP事务处理性能影响
从三次握手的细节说起 刚开始尝试使用java等后端语言写IO流,或用套接字(socket)实现简单C/S通信的同学们,常常会接触到的一个概念:就是所谓的"三次握手",socket作 ...
- Tcl与Design Compiler (三)——DC综合的流程
本文属于原创手打(有参考文献),如果有错,欢迎留言更正:此外,转载请标明出处 http://www.cnblogs.com/IClearner/ ,作者:IC_learner 1.基本流程概述 首先 ...
- Nagios工作原理
图解Nagios的工作原理 Nagios的主动模式和被动模式 被动模式:就如同上图所显示的那样,客户端起nrpe进程,服务端通过check_nrpe插件向客户端发送命令,客户端根据服务端的指示来调用相 ...
- 老李推荐:第14章7节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-装备ViewServer-获取版本号 2
代码先是发送”LIST”命令到ViewServer列出所有的打开的窗口,然后把每个窗口都保存起来.342行起按照源码的注释解析就是说:从协议版本3以后开始加入了窗口自动更新的功能,但是在此之前,如果用 ...
- 老李推荐:第14章1节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-面向控件编程VS面向坐标编程
老李推荐:第14章1节<MonkeyRunner源码剖析> HierarchyViewer实现原理-面向控件编程VS面向坐标编程 poptest是国内唯一一家培养测试开发工程师的培训机 ...
- C#, VB.NET如何加密PDF文档
在日常工作中,人们通常通过加密PDF文档的方式来保护PDF文档.不管是公司还是个人,使用PDF加密术来设置一些权限是必不可少的.为了使PDF文档既可读又不能被未授权的用户所更改,一份PDF文档往往需要 ...
- 【 Android】自定义的AlertDialog中的EditText无法调用输入法问题解决
1.问题描述: 在自定义的AlertDialog 中添加了EditText组件,但运行时怎么点EditText都无法调出软键盘: 2.原因分析: 一开始我以为EditText的focus属性没有设置好 ...
- WPF 杂谈——开篇简言。
这俩年多来笔者一直在从事关于WPF的开发.虽然不能说是专家级别的.但是对于WPF的应用还是有一定的了解.论他的灵活性决对不在WinForm之下.WPF的出现更是引发一段热议.他的何去何从更是让很多人感 ...
- 24(java_io from keyboard)
public class ReadFromKB{ public static void main(String args[]) { try { byte bArray[]=new byte[128]; ...
- 复杂SQL查询实例-5种普惠产品必须显示...
复杂SQL需求: 1.查询productCode in (1, 2, 4, 5, 7)五种 2.5种产品必须固定显示,优先显示procuct_status='1'在售产品,在售产品卖完则售罄产品顶上来 ...