个人博客:无奈何杨(wnhyang)
个人语雀:wnhyang
共享语雀:在线知识共享
Github:wnhyang - Overview
简介
标题其实是不准确的,了解过的会知道在LiteFlow
的2.12.0
已经有了决策路由的特性,但我为什么标题这么讲呢?且往下看。
因为这篇文章LF的重磅特性预告:决策路由,我一直期待着决策路由功能的发布,终于有一天它发布了!
决策路由特性来袭,LiteFlow大版本2.12.0发布,Make your code amaing!。
虽然这次是大更新,发布的不只是决策路由,但是我心心念念的决策路由并没有我期待的那样好用,因为这个版本的路由是全局匹配,没有分组或分级的概念,在实际使用中并不那么好用。虽然能通过一些代码来实现类似的分组功能,但是肯定不如框架实现的好,同时也不想因此将代码来回变动,所以通过社区向作者提意见,正好作者早有此想法,非常nice!
这次规则引擎LiteFlow发布v2.12.1版本,有多猛用过才知道,2.12.1
版本带来此功能,我也默默的将许久未编辑的《LiteFlow大版本2.12.0发布,决策路由发布》的文章重命名了标题《规则引擎LiteFlow发布v2.12.1版本,决策路由特性》。
参考
决策路由
说明
关于LiteFlow
,不想再过多介绍了。之前的文章也有说明了风控系统之普通规则条件,使用LiteFlow实现。
非常推荐通过官网来学习,很有帮助!
路由嘛,知道Nginx
吧,可以理解为location
的配置,不知道Nginx
,类比微服务网关也一样。
在2.12.0
版本加入了路由特性,新增了route
和body
标签。
<chain name="chain1">
<route>
AND(r1, r2, r3)
</route>
<body>
THEN(a, b, c);
</body>
</chain>
<chain name="chain2">
<route>
AND(OR(r4, r5), NOT(r3))
</route>
<body>
SWITCH(x).TO(d, e, f);
</body>
</chain>
同时提供了专门用于执行路由chain
的方法。
List<LiteflowResponse> responseList = flowExecutor.executeRouteChain(requestData, YourContext.class);
在此版本中存在一个很大的问题,或者说是不便。
此方法会执行所有的路由chain
,那么所有的路由chain
就被限制住了。
举个例子,如果业务需要如下这样决策流程,数据接入后想利用决策路由的特性确定跑哪个策略集,到这里决策路由还是很有用的,但是策略集下其实还有很多规则的,进入策略集后应该还要继续进行决策路由,并行跑所有规则。那么这里就出问题了,因为策略集路由明显和规则路由不是一个概念,而且还不能同时跑,是要策略路由跑完后再进行规则路由的。
在LiteFlow
的2.12.1
版本,加入了路由分组管理。
<chain name="chain1" namespace="n1">
<route>
AND(r1, r2, r3)
</route>
<body>
THEN(a, b, c);
</body>
</chain>
同时加入执行分组的方法,很好的解决了此问题。
List<LiteflowResponse> responseList = flowExecutor.executeRouteChain("n1", requestData, YourContext.class);
但是
就那上面这张图举例子,步骤有:
1、数据接入
2、判断要执行哪个策略集(唯一)
3、判断要执行策略下的哪些规则(多个)
原先判断要执行哪个策略集需要硬编码确认,有了决策路由就可以配置好route
,每个策略集route
分配好唯一的namespace
,如:每个策略集namespace
命名可以是ss-${appName}-${strategySetCode}
,ss
是strategySet
的简写,标识namespace
属于策略集,唯一性由${appName}-${strategySetCode}
动态决定。判断要执行策略下哪些规则的namespace
可以命名为rule-${strategyId}
,rule
代表规则路由,后面拼上策略id用于确认规则在哪个策略下,这样确认策略后就可以并行多个执行了。
但写着写着发现还有一个问题,当前决策路由执行好像只有这个方法,没有提供隐式子流程调用,也就说现在执行多个路由只能在不同的流程内,策略集流程执行后如果要执行规则流程的话,只能另行执行路由,两个流程独立开了,这样对我来讲其实是不对的,因为它们是公用上下文的,在同一流程内很有必要。
这个只能暂时期待住了,好像确实没有好的办法,有个方法是上下文复制传下去,但这又和LiteFlow
组件化,上下文的思想违背了,和普通的瀑布流程好像又是一样的了,而且将两个流程割裂了,不太好。
flowExecutor.executeRouteChain("n1", requestData, YourContext.class);
上下文参数注入
上下文是LiteFlow
中一个非常重要的概念,详细请查看官网🍄说明 | LiteFlow。
上下文参数注入之适用于声明式组件,声明式组件请看官网🥭什么叫声明式组件 | LiteFlow。
哈哈哈,全是看官网。。。
示例
在过去,没有上下文参数注入时,通过声明式组件获取上下文是这样的。
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "accessIn", nodeType = NodeTypeEnum.COMMON)
public void accessIn(NodeComponent bindCmp) {
DecisionRequest decisionRequest = bindCmp.getContextBean(DecisionRequest.class);
// 处理入参
Map<String, String> params = decisionRequest.getParams();
log.info("入参:{}", params);
...
}
而有了上下文参数注入特性后就可简化,如下。
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "accessIn", nodeType = NodeTypeEnum.COMMON)
public void accessIn(NodeComponent bindCmp, @LiteflowFact("params") Map<String, String> params) {
log.info("入参:{}", params);
}
在@LiteflowFact
中写的表达式,会自动的从上下文中搜索相应的参数。即使你有多个上下文,也无需去指定上下文。
但是有一种情况,在使用时要注意:假设你有两个上下文,TestContext1
和TestContext2
,在这两个上下文里都有user
这个对象,并且两个user
里的信息是不一样的。这时你通过@LiteflowFact("user") User user
这样去拿,拿到的是第一个user
,在不同环境上可能还不一样。
所以使用上下文参数注入特性时,如果有多个上下文,请确保注入的对象,在多个上下文中只有一份,否则会有错乱情况。
其实它的意义不仅仅是“简化”,对我来讲它其实是解放了声明式组件,原来在我们编写了声明式组件后,他就只是个LiteFlow
组件了,甚至不能做其他事情了。
如上例子public void accessIn(NodeComponent bindCmp)
,方法体中使用到了bindCmp
获取上下文,并使用这个上下文执行某些流程。这样的话这个方法就困死在LiteFlow
组件中了,因为我们并没有这个bindCmp
传进方法内。而加入了上下文参数注入后,此方法就变为public void accessIn(NodeComponent bindCmp, @LiteflowFact("params") Map<String, String> params)
,看似好像只是加了一个参数,其实也是加了个参数😂但是因为这个参数,间接的解放了此方法,这时我们再调用此方法不用关心bindCmp
了(前提是方法体中没用到这个),关注@LiteflowFact
修饰的参数即可。
写在最后
拙作艰辛,字句心血,望诸君垂青,多予支持,不胜感激。
个人博客:无奈何杨(wnhyang)
个人语雀:wnhyang
共享语雀:在线知识共享
Github:wnhyang - Overview