feat #I64HY4 优化 node 构建器

This commit is contained in:
gaibu 2022-12-04 16:26:08 +08:00
parent 683e784a55
commit 5707201249
4 changed files with 102 additions and 154 deletions

View File

@ -15,6 +15,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class LiteFlowNodeBuilder {
@ -24,19 +26,22 @@ public class LiteFlowNodeBuilder {
/**
* 用于维护不同类型 node 的处理逻辑
*/
private static final Map<NodeTypeEnum, Consumer<Node>> NodeBuildConsumerMap = new HashMap<NodeTypeEnum, Consumer<Node>>() {{
put(NodeTypeEnum.COMMON, _node -> FlowBus.addCommonNode(_node.getId(), _node.getName(), _node.getClazz()));
put(NodeTypeEnum.SWITCH, _node -> FlowBus.addSwitchNode(_node.getId(), _node.getName(), _node.getClazz()));
put(NodeTypeEnum.IF, _node -> FlowBus.addIfNode(_node.getId(), _node.getName(), _node.getClazz()));
put(NodeTypeEnum.FOR, _node -> FlowBus.addForNode(_node.getId(), _node.getName(), _node.getClazz()));
put(NodeTypeEnum.WHILE, _node -> FlowBus.addWhileNode(_node.getId(), _node.getName(), _node.getClazz()));
put(NodeTypeEnum.BREAK, _node -> FlowBus.addBreakNode(_node.getId(), _node.getName(), _node.getClazz()));
put(NodeTypeEnum.SCRIPT, _node -> FlowBus.addCommonScriptNode(_node.getId(), _node.getName(), _node.getClazz()));
put(NodeTypeEnum.SWITCH_SCRIPT, _node -> FlowBus.addSwitchScriptNode(_node.getId(), _node.getName(), _node.getClazz()));
put(NodeTypeEnum.IF_SCRIPT, _node -> FlowBus.addIfScriptNode(_node.getId(), _node.getName(), _node.getClazz()));
put(NodeTypeEnum.FOR_SCRIPT, _node -> FlowBus.addForScriptNode(_node.getId(), _node.getName(), _node.getClazz()));
put(NodeTypeEnum.WHILE_SCRIPT, _node -> FlowBus.addWhileScriptNode(_node.getId(), _node.getName(), _node.getClazz()));
put(NodeTypeEnum.BREAK_SCRIPT, _node -> FlowBus.addBreakScriptNode(_node.getId(), _node.getName(), _node.getClazz()));
private static final Map<NodeTypeEnum, BiConsumer<Node, NodeTypeEnum>> NodeBuildConsumerMap = new HashMap<NodeTypeEnum, BiConsumer<Node, NodeTypeEnum>>() {{
// 用于处理普通 node
put(NodeTypeEnum.COMMON, (_node, nodeType) -> FlowBus.addNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
put(NodeTypeEnum.SWITCH, (_node, nodeType) -> FlowBus.addNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
put(NodeTypeEnum.IF, (_node, nodeType) -> FlowBus.addNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
put(NodeTypeEnum.FOR, (_node, nodeType) -> FlowBus.addNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
put(NodeTypeEnum.WHILE, (_node, nodeType) -> FlowBus.addNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
put(NodeTypeEnum.BREAK, (_node, nodeType) -> FlowBus.addNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
// 用于处理脚本 node
put(NodeTypeEnum.SCRIPT, (_node, nodeType) -> FlowBus.addScriptNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
put(NodeTypeEnum.SWITCH_SCRIPT, (_node, nodeType) -> FlowBus.addScriptNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
put(NodeTypeEnum.IF_SCRIPT, (_node, nodeType) -> FlowBus.addScriptNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
put(NodeTypeEnum.FOR_SCRIPT, (_node, nodeType) -> FlowBus.addScriptNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
put(NodeTypeEnum.WHILE_SCRIPT, (_node, nodeType) -> FlowBus.addScriptNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
put(NodeTypeEnum.BREAK_SCRIPT, (_node, nodeType) -> FlowBus.addScriptNode(_node.getId(), _node.getName(), nodeType, _node.getClazz()));
}};
private final Node node;
@ -153,7 +158,13 @@ public class LiteFlowNodeBuilder {
public void build() {
checkBuild();
try {
NodeBuildConsumerMap.get(this.node.getType()).accept(this.node);
for (Map.Entry<NodeTypeEnum, BiConsumer<Node, NodeTypeEnum>> entry : NodeBuildConsumerMap.entrySet()) {
NodeTypeEnum nodeType = entry.getKey();
if (nodeType == this.node.getType()) {
entry.getValue().accept(this.node, nodeType);
return;
}
}
} catch (Exception e) {
String errMsg = StrUtil.format("An exception occurred while building the node[{}],{}", this.node.getId(), e.getMessage());
LOG.error(errMsg, e);

View File

@ -36,6 +36,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@ -43,6 +44,7 @@ import java.util.stream.Collectors;
/**
* 流程元数据类
*
* @author Bryan.Zhang
*/
public class FlowBus {
@ -53,16 +55,28 @@ public class FlowBus {
private static final Map<String, Node> nodeMap = new CopyOnWriteHashMap<>();
/**
* 用于维护脚本类型和脚本 cmp 的映射关系
*/
private static final Map<NodeTypeEnum, Class<?>> ScriptComponentClassMap = new HashMap<NodeTypeEnum, Class<?>>() {{
put(NodeTypeEnum.SCRIPT, ScriptCommonComponent.class);
put(NodeTypeEnum.SWITCH_SCRIPT, ScriptSwitchComponent.class);
put(NodeTypeEnum.IF_SCRIPT, ScriptIfComponent.class);
put(NodeTypeEnum.FOR_SCRIPT, ScriptForComponent.class);
put(NodeTypeEnum.WHILE_SCRIPT, ScriptWhileComponent.class);
put(NodeTypeEnum.BREAK_SCRIPT, ScriptBreakComponent.class);
}};
private FlowBus() {
}
public static Chain getChain(String id){
public static Chain getChain(String id) {
return chainMap.get(id);
}
//这一方法主要用于第一阶段chain的预装载
public static void addChain(String chainName){
if (!chainMap.containsKey(chainName)){
public static void addChain(String chainName) {
if (!chainMap.containsKey(chainName)) {
chainMap.put(chainName, new Chain(chainName));
}
}
@ -88,133 +102,53 @@ public class FlowBus {
//根据class来猜测类型
NodeTypeEnum type = NodeTypeEnum.guessType(nodeComponent.getClass());
if (type == null){
if (type == null) {
throw new NullNodeTypeException(StrUtil.format("node type is null for node[{}]", nodeId));
}
nodeMap.put(nodeId, new Node(ComponentInitializer.loadInstance().initComponent(nodeComponent, type, null, nodeId)));
}
public static void addCommonNode(String nodeId, String name, String cmpClazzStr){
/**
* 添加 node
*
* @param nodeId 节点id
* @param name 节点名称
* @param type 节点类型
* @param cmpClazz 节点组件类
*/
public static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz) {
addNode(nodeId, name, type, cmpClazz, null);
}
/**
* 添加 node
*
* @param nodeId 节点id
* @param name 节点名称
* @param nodeType 节点类型
* @param cmpClazzStr 节点组件类路径
*/
public static void addNode(String nodeId, String name, NodeTypeEnum nodeType, String cmpClazzStr) {
Class<?> cmpClazz;
try{
try {
cmpClazz = Class.forName(cmpClazzStr);
}catch (Exception e){
throw new ComponentCannotRegisterException(e.getMessage());
}
addNode(nodeId, name, NodeTypeEnum.COMMON, cmpClazz, null);
}
public static void addCommonNode(String nodeId, String name, Class<?> cmpClazz){
addNode(nodeId, name, NodeTypeEnum.COMMON, cmpClazz, null);
}
public static void addSwitchNode(String nodeId, String name, String cmpClazzStr){
Class<?> cmpClazz;
try{
cmpClazz = Class.forName(cmpClazzStr);
}catch (Exception e){
throw new ComponentCannotRegisterException(e.getMessage());
}
addNode(nodeId, name, NodeTypeEnum.SWITCH, cmpClazz, null);
}
public static void addSwitchNode(String nodeId, String name, Class<?> cmpClazz){
addNode(nodeId, name, NodeTypeEnum.SWITCH, cmpClazz, null);
}
public static void addIfNode(String nodeId, String name, String cmpClazzStr){
Class<?> cmpClazz;
try{
cmpClazz = Class.forName(cmpClazzStr);
}catch (Exception e){
throw new ComponentCannotRegisterException(e.getMessage());
}
addNode(nodeId, name, NodeTypeEnum.IF, cmpClazz, null);
}
public static void addIfNode(String nodeId, String name, Class<?> cmpClazz){
addNode(nodeId, name, NodeTypeEnum.IF, cmpClazz, null);
}
public static void addForNode(String nodeId, String name, String cmpClazzStr){
Class<?> cmpClazz;
try{
cmpClazz = Class.forName(cmpClazzStr);
}catch (Exception e){
throw new ComponentCannotRegisterException(e.getMessage());
}
addNode(nodeId, name, NodeTypeEnum.FOR, cmpClazz, null);
}
public static void addForNode(String nodeId, String name, Class<?> cmpClazz){
addNode(nodeId, name, NodeTypeEnum.FOR, cmpClazz, null);
}
public static void addWhileNode(String nodeId, String name, String cmpClazzStr){
Class<?> cmpClazz;
try{
cmpClazz = Class.forName(cmpClazzStr);
}catch (Exception e){
throw new ComponentCannotRegisterException(e.getMessage());
}
addNode(nodeId, name, NodeTypeEnum.WHILE, cmpClazz, null);
}
public static void addWhileNode(String nodeId, String name, Class<?> cmpClazz){
addNode(nodeId, name, NodeTypeEnum.WHILE, cmpClazz, null);
}
public static void addBreakNode(String nodeId, String name, String cmpClazzStr){
Class<?> cmpClazz;
try{
cmpClazz = Class.forName(cmpClazzStr);
}catch (Exception e){
throw new ComponentCannotRegisterException(e.getMessage());
}
addNode(nodeId, name, NodeTypeEnum.BREAK, cmpClazz, null);
}
public static void addBreakNode(String nodeId, String name, Class<?> cmpClazz){
addNode(nodeId, name, NodeTypeEnum.BREAK, cmpClazz, null);
}
public static void addCommonScriptNode(String nodeId, String name, String script){
addNode(nodeId, name, NodeTypeEnum.SCRIPT, ScriptCommonComponent.class, script);
}
public static void addSwitchScriptNode(String nodeId, String name, String script){
addNode(nodeId, name, NodeTypeEnum.SWITCH_SCRIPT, ScriptSwitchComponent.class, script);
}
public static void addIfScriptNode(String nodeId, String name, String script){
addNode(nodeId, name, NodeTypeEnum.IF_SCRIPT, ScriptIfComponent.class, script);
}
public static void addForScriptNode(String nodeId, String name, String script){
addNode(nodeId, name, NodeTypeEnum.FOR_SCRIPT, ScriptForComponent.class, script);
}
public static void addWhileScriptNode(String nodeId, String name, String script){
addNode(nodeId, name, NodeTypeEnum.WHILE_SCRIPT, ScriptWhileComponent.class, script);
}
public static void addBreakScriptNode(String nodeId, String name, String script){
addNode(nodeId, name, NodeTypeEnum.BREAK_SCRIPT, ScriptBreakComponent.class, script);
}
public static void addNode(String nodeId, String name, NodeTypeEnum nodeType, String cmpClazzStr){
Class<?> cmpClazz;
try{
cmpClazz = Class.forName(cmpClazzStr);
}catch (Exception e){
} catch (Exception e) {
throw new ComponentCannotRegisterException(e.getMessage());
}
addNode(nodeId, name, nodeType, cmpClazz, null);
}
public static void addScriptNode(String nodeId, String name, NodeTypeEnum nodeType, String script){
addNode(nodeId, name, nodeType, ScriptCommonComponent.class, script);
/**
* 添加脚本 node
*
* @param nodeId 节点id
* @param name 节点名称
* @param nodeType 节点类型
* @param script 脚本
*/
public static void addScriptNode(String nodeId, String name, NodeTypeEnum nodeType, String script) {
addNode(nodeId, name, nodeType, ScriptComponentClassMap.get(nodeType), script);
}
private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz, String script) {
@ -222,7 +156,7 @@ public class FlowBus {
//判断此类是否是声明式的组件如果是声明式的组件就用动态代理生成实例
//如果不是声明式的就用传统的方式进行判断
List<NodeComponent> cmpInstances = new ArrayList<>();
if (LiteFlowProxyUtil.isDeclareCmp(cmpClazz)){
if (LiteFlowProxyUtil.isDeclareCmp(cmpClazz)) {
//这里的逻辑要仔细看下
//如果是spring体系把原始的类往spring上下文中进行注册那么会走到ComponentScanner中
//由于ComponentScanner中已经对原始类进行了动态代理出来的对象已经变成了动态代理类所以这时候的bean已经是NodeComponent的子类了
@ -231,16 +165,16 @@ public class FlowBus {
//这里用ContextAware的spi机制来判断是否spring体系
ContextAware contextAware = ContextAwareHolder.loadContextAware();
Object bean = ContextAwareHolder.loadContextAware().registerBean(nodeId, cmpClazz);
if (LocalContextAware.class.isAssignableFrom(contextAware.getClass())){
if (LocalContextAware.class.isAssignableFrom(contextAware.getClass())) {
cmpInstances = LiteFlowProxyUtil.proxy2NodeComponent(bean, nodeId);
}else {
} else {
cmpInstances = ListUtil.toList((NodeComponent) bean);
}
}else{
} else {
//以node方式配置本质上是为了适配无spring的环境如果有spring环境其实不用这么配置
//这里的逻辑是判断是否能从spring上下文中取到如果没有spring则就是new instance了
//如果是script类型的节点因为class只有一个所以也不能注册进spring上下文注册的时候需要new Instance
if (!type.isScript()){
if (!type.isScript()) {
cmpInstances = ListUtil.toList((NodeComponent) ContextAwareHolder.loadContextAware().registerOrGet(nodeId, cmpClazz));
}
// 去除null元素
@ -268,11 +202,11 @@ public class FlowBus {
Node node = nodes.get(i);
NodeComponent cmpInstance = cmpInstances.get(i);
//如果是脚本节点则还要加载script脚本
if (type.isScript()){
if (StrUtil.isNotBlank(script)){
if (type.isScript()) {
if (StrUtil.isNotBlank(script)) {
node.setScript(script);
((ScriptComponent)cmpInstance).loadScript(script);
}else{
((ScriptComponent) cmpInstance).loadScript(script);
} else {
String errorMsg = StrUtil.format("script for node[{}] is empty", nodeId);
throw new ScriptLoadException(errorMsg);
}
@ -283,7 +217,7 @@ public class FlowBus {
}
} catch (Exception e) {
String error = StrUtil.format("component[{}] register error", StrUtil.isEmpty(name)?nodeId:StrUtil.format("{}({})",nodeId,name));
String error = StrUtil.format("component[{}] register error", StrUtil.isEmpty(name) ? nodeId : StrUtil.format("{}({})", nodeId, name));
LOG.error(e.getMessage());
throw new ComponentCannotRegisterException(error);
}
@ -297,19 +231,19 @@ public class FlowBus {
//那condNodeMap共用有关系么原则上没有关系但是从设计理念上以后应该要分开
//tag和condNodeMap这2个属性不属于全局概念属于每个chain范围的属性
public static Node copyNode(String nodeId) {
try{
try {
Node node = nodeMap.get(nodeId);
return node.copy();
}catch (Exception e){
} catch (Exception e) {
return null;
}
}
public static Map<String, Node> getNodeMap(){
public static Map<String, Node> getNodeMap() {
return nodeMap;
}
public static Map<String, Chain> getChainMap(){
public static Map<String, Chain> getChainMap() {
return chainMap;
}
@ -321,12 +255,13 @@ public class FlowBus {
public static void cleanScriptCache() {
//如果引入了脚本组件SPI则还需要清理脚本的缓存
try{
try {
ScriptExecutor scriptExecutor = ScriptExecutorFactory.loadInstance().getScriptExecutor();
if (ObjectUtil.isNotNull(scriptExecutor)){
if (ObjectUtil.isNotNull(scriptExecutor)) {
scriptExecutor.cleanCache();
}
}catch (ScriptSpiException ignored){}
} catch (ScriptSpiException ignored) {
}
}
public static void refreshFlowMetaData(FlowParserTypeEnum type, String content) throws Exception {
@ -339,18 +274,18 @@ public class FlowBus {
}
}
public static boolean removeChain(String chainId){
if (containChain(chainId)){
public static boolean removeChain(String chainId) {
if (containChain(chainId)) {
chainMap.remove(chainId);
return true;
}else{
} else {
String errMsg = StrUtil.format("cannot find the chain[{}]", chainId);
LOG.error(errMsg);
return false;
}
}
public static void removeChain(String... chainIds){
public static void removeChain(String... chainIds) {
Arrays.stream(chainIds).forEach(FlowBus::removeChain);
}
}

View File

@ -2,6 +2,7 @@ package com.yomahub.liteflow.test.flowmeta;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.core.FlowExecutorHolder;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.property.LiteflowConfig;
@ -26,7 +27,7 @@ public class FlowMetaTest extends BaseTest {
//测试动态添加元信息节点
@Test
public void testFlowMeta() {
FlowBus.addCommonNode("d", "d组件", DCmp.class);
FlowBus.addNode("d", "d组件", NodeTypeEnum.COMMON, DCmp.class);
LiteflowResponse response= flowExecutor.execute2Resp("chain1", "it's a request");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("a==>b==>c==>d[d组件]", response.getExecuteStepStr());

View File

@ -1,6 +1,7 @@
package com.yomahub.liteflow.test.flowmeta;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.slot.DefaultContext;
@ -24,7 +25,7 @@ public class FlowMetaELSpringTest extends BaseTest {
//测试动态添加元信息节点
@Test
public void testFlowMeta() {
FlowBus.addCommonNode("d", "d组件", DCmp.class);
FlowBus.addNode("d", "d组件", NodeTypeEnum.COMMON, DCmp.class);
LiteflowResponse response= flowExecutor.execute2Resp("chain1", "it's a request");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("a==>b==>c==>d[d组件]", response.getExecuteStepStr());