聊一聊组件化可编排编程

今天给大家介绍一款轻量、快速、稳定可编排的组件式规则引擎框架LiteFlow。

前言

在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部资源调取,内部其他系统RPC调用等等。时间一长,项目几经易手,维护的成本得就会越来越高。各种硬代码判断,分支条件越来越多。代码的抽象,复用率也越来越低,各个模块之间的耦合度很高。一小段逻辑的变动,会影响到其他模块,需要进行完整回归测试来验证。如要灵活改变业务流程的顺序,则要进行代码大改动进行抽象,重新写方法。实时热变更业务流程,几乎很难实现。

LiteFlow为解耦逻辑而生,为编排而生,在使用LiteFlow之后,你会发现打造一个低耦合,灵活的系统会变得易如反掌!

1、LiteFlow框架的优势

如果你要对复杂业务逻辑进行新写或者重构,用LiteFlow最合适不过。它是一个轻量,快速的组件式规则引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件,并支持热加载规则配置,实现即时修改。

使用LiteFlow,你需要去把复杂的业务逻辑按代码片段拆分成一个个小组件,并定义一个规则流程配置。这样,所有的组件,都能按照你的规则配置去进行复杂的流转。

2、LiteFlow的设计原则

LiteFlow是基于工作台模式进行设计的,何谓工作台模式?

n个工人按照一定顺序围着一张工作台,按顺序各自生产零件,生产的零件最终能组装成一个机器,每个工人只需要完成自己手中零件的生产,而无需知道其他工人生产的内容。每一个工人生产所需要的资源都从工作台上拿取,如果工作台上有生产所必须的资源,则就进行生产,若是没有,就等到有这个资源。每个工人所做好的零件,也都放在工作台上。

这个模式有几个好处:

  • 每个工人无需和其他工人进行沟通。工人只需要关心自己的工作内容和工作台上的资源。这样就做到了每个工人之间的解耦和无差异性。
  • 即便是工人之间调换位置,工人的工作内容和关心的资源没有任何变化。这样就保证了每个工人的稳定性。
  • 如果是指派某个工人去其他的工作台,工人的工作内容和需要的资源依旧没有任何变化,这样就做到了工人的可复用性。
  • 因为每个工人不需要和其他工人沟通,所以可以在生产任务进行时进行实时工位更改:替换,插入,撤掉一些工人,这样生产任务也能实时的被更改。这样就保证了整个生产任务的灵活性。

这个模式映射到LiteFlow框架里,工人就是组件,工人坐的顺序就是流程配置,工作台就是上下文,资源就是参数,最终组装的这个机器就是这个业务。正因为有这些特性,所以LiteFlow能做到统一解耦的组件和灵活的装配。

3、LiteFlow不适用于哪些场景

LiteFlow只做基于逻辑的流转,而不做基于角色任务的流转。如果你想做基于角色任务的流转,推荐使用flowable (opens new window)activiti (opens new window)这2个框架。

4、LiteFlow适用于哪些场景

LiteFlow适用于拥有复杂逻辑的业务,比如说价格引擎,下单流程等,这些业务往往都拥有很多步骤,这些步骤完全可以按照业务粒度拆分成一个个独立的组件,进行装配复用变更。使用LiteFlow,你会得到一个灵活度高,扩展性很强的系统。因为组件之间相互独立,也可以避免改一处而动全身的这样的风险。

5、LiteFlow特性

  • 组件定义统一: 所有的逻辑都是组件,为所有的逻辑提供统一化的组件实现方式,小身材,大能量。
  • 规则轻量: 基于规则文件来编排流程,学习规则表达式入门只需要5分钟,一看既懂。
  • 规则多样化: 规则支持xml、json、yml三种规则文件写法方式,喜欢哪种用哪个。
  • 任意编排: 同步异步混编,再复杂的逻辑过程,利用LiteFlow的规则,都是易如反掌,看规则文件就能知道逻辑是如何运转的,所见即所得。
  • 规则能从任意地方加载: 框架中提供本地文件配置源和zk配置源的实现,也提供了扩展接口,您可以把规则存储在任何地方。
  • 优雅热刷新机制: 规则变化,无需重启您的应用,即时改变应用的规则。高并发下不会因为刷新规则导致正在执行的规则有任何错乱。
  • 支持广泛: 不管你的项目是不是基于Springboot,Spring还是任何其他java框架构建,LiteFlow都能游刃有余。
  • JDK支持: 从JDK8到JDK17,统统支持。无需担心JDK版本。
  • 脚本语言支持: 可以定义脚本语言节点,支持QLExpress和Groovy两种脚本。未来还会支持更多的脚本语言。
  • 规则嵌套支持: 只要你想的出,你可以利用简单的表达式完成多重嵌套的复杂逻辑编排。
  • 组件重试支持: 组件可以支持重试,每个组件均可自定义重试配置和指定异常。
  • 上下文隔离机制: 可靠的上下文隔离机制,你无需担心高并发情况下的数据串流。
  • 声明式组件支持: 你可以让你的任意类秒变组件。
  • 详细的步骤信息: 你的链路如何执行的,每个组件耗时多少,报了什么错,一目了然。
  • 稳定可靠: 历时2年多的迭代,在各大公司的核心系统上稳定运行。
  • 性能卓越: 框架本身几乎不消耗额外性能,性能取决你的组件执行效率。
  • 自带简单监控: 框架内自带一个命令行的监控,能够知道每个组件的运行耗时排行。

6、SpringBoot场景应用

6.1 依赖

LiteFlow提供了liteflow-spring-boot-starter依赖包,提供自动装配功能。具体依赖内容如下:

<dependency>
	<groupId>com.yomahub</groupId>
	<artifactId>liteflow-spring-boot-starter</artifactId>
	<version>2.8.5</version>
</dependency>

6.2 组件的定义

实现第一个组件

@Component("a")
//@LiteflowComponent(id = "a", name = "A组件") 也可使用该注解,给组件起别名,方便日志查看
public class ACmp extends NodeComponent {
   

	private static final Logger log = LoggerFactory.getLogger(ACmp.class);

	@Override
	public void process() {
   
		
		log.info("执行了A组件。。。");
	}
}

以此类推再分别定义b,c组件,Bcmp和CCmp。在这里,不再详细列出。

6.3 SpringBoot配置文件

然后,在SpringBoot的application.properties里添加如下配置(application.yml内容类似):

liteflow.rule-source=config/flow.el.xml

6.4 定义规则文件

同时,你得在resources下的config/flow.el.xml中定义规则:

<?xml version="1.0" encoding="UTF-8"?>
<flow>
    <chain name="chain1">
        THEN(a, b, c);
    </chain>
</flow>

6.5 编写SpringBoot启动代码

@SpringBootApplication
public class MessageDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(MessageDemoApplication.class, args);
    }

}

编写SpringBoot启动时运行代码:

@Component
public class ChainExecute implements CommandLineRunner {

    private static final Logger log = LoggerFactory.getLogger(ChainExecute.class);

    @Resource
    private FlowExecutor flowExecutor;
    
    @Override
    public void run(String... args) throws Exception {
        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "agrs");
    }
}

6.6 执行第一个编排程序

运行MessageDemoApplication打印出下面日志(为了方便查看,日志经过整理):

INFO ACmp: 执行了A组件。。。
INFO BCmp: 执行了B组件。。。
INFO CCmp: 执行了C组件。。。

6.7 调整编排顺序

将编排顺序调整从THEN(a, b, c)调整为THEN(a, c, b)运行,查看日志内容如下:

INFO ACmp: 执行了A组件。。。
INFO CCmp: 执行了C组件。。。
INFO BCmp: 执行了B组件。。。

7、组件讲解

在LiteFlow里,目前包含普通组件、选择组件 和 条件组件。
普通组件需要继承 NodeComponent类、选择组件需要继承 NodeSwitchComponent、条件组件需要继承 NodeIfComponent。在第6节里,我们主要讲解了普通组件,这里不再做示例讲解。

7.1 组件方法

可覆盖方法

  • isAccess

推荐实现isAccess方法,表示是否进入该节点,可以用于业务参数的预先判断

  • isContinueOnError

表示出错是否继续往下执行下一个组件,默认为false

  • isEnd

如果覆盖后,返回true,则表示在这个组件执行完之后立马终止整个流程。对于这种方式,由于是用户主动结束的流程,属于正常结束,所以最终的isSuccess是为true的。

  • beforeProcess和afterProcess

流程的前置和后置处理器,其中前置处理器,在isAccess 之后执行。

  • onSuccess和onError

流程的成功失败事件回调

this关键字可以调用的方法

在组件节点里,随时可以通过方法this.getContextBean(clazz)获取当前你自己定义的上下文,从而可以获取任何数据。

  • getNodeId
    获取组件ID。

  • getName
    获取组件别名。

  • getChainName
    获取当前执行的流程名称。

  • getRequestData
    获取流程的初始参数。

  • setIsEnd
    表示是否立即结束整个流程 ,用法为this.setIsEnd(true)。对于这种方式,由于是用户主动结束的流程,属于正常结束,所以最终的isSuccess是为true的。

  • getTag
    获取这个组件的标签信息。

  • invoke和invoke2Response
    调用隐式流程。

7.2 选择组件

在实际业务中,往往要通过动态的业务逻辑判断到底接下去该执行哪一个节点,这就引申出了选择节点,选择节点可以用于SWITCH关键字中。
将组件A改造成以下代码:

@Component("a")
//@LiteflowComponent(id = "a", name = "A组件")
public class ACmp extends NodeSwitchComponent {

	private static final Logger log = LoggerFactory.getLogger(ACmp.class);

	@Override
	public String processSwitch() throws Exception {
		log.info("执行了选择A组件。。。");
		String para = this.getRequestData();
		if (para != null) {
			return "c";
		} else {
			return "b";
		}
	}

}

表达式调整为:

<chain name="chain1">
    SWITCH(a).to(b, c);
</chain>

重新执行后,运行结果如下:

INFO ACmp: 执行了选择A组件。。。
INFO CCmp: 执行了C组件。。。

7.3 条件组件

条件组件,也可以称之为IF组件,返回是一个true/false。可用于IF...ELIF...ELSE等关键字。
添加XCmp组件,代码如下:

@Component("x")
public class XCmp extends NodeIfComponent {
	private static final Logger log = LoggerFactory.getLogger(XCmp.class);

	@Override
	public boolean processIf() throws Exception {
		log.info("执行了条件X组件。。。");
		return true;
	}
}

表达式调整为:

<chain name="chain1">
    IF(x, a, b);
</chain>

执行程序,运行结果如下:

INFO XCmp:执行了条件X组件。。。
INFO ACmp: 执行了选择A组件。。。

我们发现,在执行选择A组件后,并没出现7.2的执行结果,可以调整EL表达式,达到预期结果。

<chain name="chain1">
    IF(x, SWITCH(a).to(b, c), b);
</chain>

再次执行:

INFO XCmp:执行了条件X组件。。。
INFO ACmp: 执行了选择A组件。。。
INFO CCmp: 执行了C组件。。。

8、EL规则

在上面的示例中,我们体验到规则表达式的强大。一切复杂的流程在LiteFlow表达式的加持下,都异常丝滑简便。我们只需要很短的时间即可学会如何写一个很复杂流程的表达式。

8.1 串行编排

如果你要依次执行a,b,c,d四个组件,你可以用THEN关键字,需要注意的是,THEN必须大写。

<chain name="chain1">
    THEN(a, b, c, d);
</chain>

图示为:

a
b
c
d

8.2 并行编排

使用用WHEN将a,b,c并行编排。

<chain name="chain1">
    WHEN(a, b, c);
</chain>

然后,我们使用 THENWHEN 进行混合编排。

<chain name="chain1">
    THEN(a, WHEN(b, c, d), e);
</chain>

图示为:

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值