diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java
index a5e26cab9..cb6fd7748 100644
--- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java
+++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java
@@ -4,15 +4,15 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.InstructionSet;
import com.ql.util.express.exception.QLException;
import com.yomahub.liteflow.builder.el.operator.*;
import com.yomahub.liteflow.common.ChainConstant;
-import com.yomahub.liteflow.exception.DataNotFoundException;
-import com.yomahub.liteflow.exception.ELParseException;
-import com.yomahub.liteflow.exception.FlowSystemException;
+import com.yomahub.liteflow.exception.*;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.flow.element.Chain;
import com.yomahub.liteflow.flow.element.Condition;
@@ -34,6 +34,8 @@ public class LiteFlowChainELBuilder {
private static final LFLog LOG = LFLoggerManager.getLogger(LiteFlowChainELBuilder.class);
+ private static ObjectMapper objectMapper =new ObjectMapper();
+
private Chain chain;
/**
@@ -196,6 +198,16 @@ public class LiteFlowChainELBuilder {
if (CollUtil.isNotEmpty(errorList)) {
throw new RuntimeException(CollUtil.join(errorList, ",", "[", "]"));
}
+ // 对每一个 chain 进行循环引用检测
+ try {
+ objectMapper.writeValueAsString(this.chain);
+ } catch (Exception e) {
+ if (e instanceof JsonMappingException) {
+ throw new CyclicDependencyException(StrUtil.format("There is a circular dependency in the chain[{}], please check carefully.", chain.getChainId(), e));
+ } else {
+ throw new ParseException(e.getMessage());
+ }
+ }
}
/**
diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java
index 5d90e3c16..269a4dd62 100644
--- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java
+++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/Node.java
@@ -8,23 +8,23 @@
package com.yomahub.liteflow.flow.element;
-import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.ttl.TransmittableThreadLocal;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.ExecuteTypeEnum;
+import com.yomahub.liteflow.enums.NodeTypeEnum;
+import com.yomahub.liteflow.exception.ChainEndException;
+import com.yomahub.liteflow.exception.FlowSystemException;
+import com.yomahub.liteflow.flow.executor.NodeExecutor;
+import com.yomahub.liteflow.flow.executor.NodeExecutorHelper;
import com.yomahub.liteflow.log.LFLog;
import com.yomahub.liteflow.log.LFLoggerManager;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.property.LiteflowConfigGetter;
import com.yomahub.liteflow.slot.DataBus;
import com.yomahub.liteflow.slot.Slot;
-import com.yomahub.liteflow.flow.executor.NodeExecutor;
-import com.yomahub.liteflow.flow.executor.NodeExecutorHelper;
-import com.yomahub.liteflow.enums.ExecuteTypeEnum;
-import com.yomahub.liteflow.enums.NodeTypeEnum;
-import com.yomahub.liteflow.exception.ChainEndException;
-import com.yomahub.liteflow.exception.FlowSystemException;
/**
* Node节点,实现可执行器 Node节点并不是单例的,每构建一次都会copy出一个新的实例
@@ -47,6 +47,8 @@ public class Node implements Executable, Cloneable, Rollbackable{
private String language;
+ // 增加该注解,避免在使用 Jackson 序列化检测循环引用时出现不必要异常
+ @JsonIgnore
private NodeComponent instance;
private String tag;
diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java
index eb239f76f..89eb4177b 100644
--- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java
+++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/helper/ParserHelper.java
@@ -13,7 +13,10 @@ import com.yomahub.liteflow.flow.FlowBus;
import org.dom4j.Document;
import org.dom4j.Element;
-import java.util.*;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.regex.Pattern;
@@ -237,8 +240,10 @@ public class ParserHelper {
// 构建chainBuilder
String chainId = Optional.ofNullable(chainNode.get(ID)).orElse(chainNode.get(NAME)).textValue();
String el = chainNode.get(VALUE).textValue();
- LiteFlowChainELBuilder chainELBuilder = LiteFlowChainELBuilder.createChain().setChainId(chainId);
- chainELBuilder.setEL(el).build();
+ LiteFlowChainELBuilder.createChain()
+ .setChainId(chainId)
+ .setEL(el)
+ .build();
}
/**
@@ -250,8 +255,10 @@ public class ParserHelper {
String chainId = Optional.ofNullable(e.attributeValue(ID)).orElse(e.attributeValue(NAME));
String text = e.getText();
String el = RegexUtil.removeComments(text);
- LiteFlowChainELBuilder chainELBuilder = LiteFlowChainELBuilder.createChain().setChainId(chainId);
- chainELBuilder.setEL(el).build();
+ LiteFlowChainELBuilder.createChain()
+ .setChainId(chainId)
+ .setEL(el)
+ .build();
}
/**
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowInDifferentConfigTest.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowInDifferentConfigTest.java
new file mode 100644
index 000000000..3017205c4
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowInDifferentConfigTest.java
@@ -0,0 +1,31 @@
+
+package com.yomahub.liteflow.test.endlessLoop;
+
+import com.yomahub.liteflow.core.FlowExecutorHolder;
+import com.yomahub.liteflow.exception.CyclicDependencyException;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+
+/**
+ * 测试多文件情况下 chain 死循环逻辑
+ *
+ * @author luo yi
+ * @since 2.11.1
+ */
+public class FlowInDifferentConfigTest extends BaseTest {
+
+ // 测试 chain 死循环
+ @Test
+ public void testChainEndlessLoop() {
+ Assertions.assertThrows(CyclicDependencyException.class, () -> {
+ LiteflowConfig config = LiteflowConfigGetter.get();
+ config.setRuleSource("endlessLoop/flow-main.el.xml,endlessLoop/flow-sub1.el.xml");
+ FlowExecutorHolder.loadInstance(config);
+ });
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowJsonTest.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowJsonTest.java
new file mode 100644
index 000000000..5f36f22aa
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowJsonTest.java
@@ -0,0 +1,29 @@
+package com.yomahub.liteflow.test.endlessLoop;
+
+import com.yomahub.liteflow.core.FlowExecutorHolder;
+import com.yomahub.liteflow.exception.CyclicDependencyException;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * 测试 json 文件情况下 chain 死循环逻辑
+ *
+ * @author luo yi
+ * @since 2.11.1
+ */
+public class FlowJsonTest extends BaseTest {
+
+ // 测试 chain 死循环
+ @Test
+ public void testChainEndlessLoop() {
+ Assertions.assertThrows(CyclicDependencyException.class, () -> {
+ LiteflowConfig config = LiteflowConfigGetter.get();
+ config.setRuleSource("endlessLoop/flow.el.json");
+ FlowExecutorHolder.loadInstance(config);
+ });
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowXMLTest.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowXMLTest.java
new file mode 100644
index 000000000..3091e60a9
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowXMLTest.java
@@ -0,0 +1,29 @@
+package com.yomahub.liteflow.test.endlessLoop;
+
+import com.yomahub.liteflow.core.FlowExecutorHolder;
+import com.yomahub.liteflow.exception.CyclicDependencyException;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * 测试 xml 文件情况下 chain 死循环逻辑
+ *
+ * @author luo yi
+ * @since 2.11.1
+ */
+public class FlowXMLTest extends BaseTest {
+
+ // 测试 chain 死循环
+ @Test
+ public void testChainEndlessLoop() {
+ Assertions.assertThrows(CyclicDependencyException.class, () -> {
+ LiteflowConfig config = LiteflowConfigGetter.get();
+ config.setRuleSource("endlessLoop/flow.el.xml");
+ FlowExecutorHolder.loadInstance(config);
+ });
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowYMLTest.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowYMLTest.java
new file mode 100644
index 000000000..654cf63db
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowYMLTest.java
@@ -0,0 +1,29 @@
+package com.yomahub.liteflow.test.endlessLoop;
+
+import com.yomahub.liteflow.core.FlowExecutorHolder;
+import com.yomahub.liteflow.exception.CyclicDependencyException;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * 测试 yml 文件情况下 chain 死循环逻辑
+ *
+ * @author luo yi
+ * @since 2.11.1
+ */
+public class FlowYMLTest extends BaseTest {
+
+ // 测试 chain 死循环
+ @Test
+ public void testChainEndlessLoop() {
+ Assertions.assertThrows(CyclicDependencyException.class, () -> {
+ LiteflowConfig config = LiteflowConfigGetter.get();
+ config.setRuleSource("endlessLoop/flow.el.yml");
+ FlowExecutorHolder.loadInstance(config);
+ });
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ACmp.java
new file mode 100644
index 000000000..a98b541c2
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ACmp.java
@@ -0,0 +1,12 @@
+package com.yomahub.liteflow.test.endlessLoop.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+
+public class ACmp extends NodeComponent {
+
+ @Override
+ public void process() {
+ System.out.println("Acomp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/BCmp.java
new file mode 100644
index 000000000..f3699371e
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/BCmp.java
@@ -0,0 +1,12 @@
+package com.yomahub.liteflow.test.endlessLoop.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+
+public class BCmp extends NodeComponent {
+
+ @Override
+ public void process() {
+ System.out.println("Bcomp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/CCmp.java
new file mode 100644
index 000000000..d9abde6be
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/CCmp.java
@@ -0,0 +1,12 @@
+package com.yomahub.liteflow.test.endlessLoop.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+
+public class CCmp extends NodeComponent {
+
+ @Override
+ public void process() throws Exception {
+ System.out.println("Ccomp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/DCmp.java
new file mode 100644
index 000000000..b5ffafe78
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/DCmp.java
@@ -0,0 +1,12 @@
+package com.yomahub.liteflow.test.endlessLoop.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+
+public class DCmp extends NodeComponent {
+
+ @Override
+ public void process() throws Exception {
+ System.out.println("Dcomp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ECmp.java
new file mode 100644
index 000000000..fce4af378
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ECmp.java
@@ -0,0 +1,12 @@
+package com.yomahub.liteflow.test.endlessLoop.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+
+public class ECmp extends NodeComponent {
+
+ @Override
+ public void process() throws Exception {
+ System.out.println("Ecomp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow-main.el.xml b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow-main.el.xml
new file mode 100644
index 000000000..2100fc65f
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow-main.el.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+ THEN(a, b, chain2);
+
+
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow-sub1.el.xml b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow-sub1.el.xml
new file mode 100644
index 000000000..39b89324e
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow-sub1.el.xml
@@ -0,0 +1,6 @@
+
+
+
+ THEN(b, a, chain1);
+
+
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow.el.json b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow.el.json
new file mode 100644
index 000000000..b63faed4d
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow.el.json
@@ -0,0 +1,42 @@
+{
+ "flow": {
+ "nodes": {
+ "node": [
+ {
+ "id": "a",
+ "class": "com.yomahub.liteflow.test.endlessLoop.cmp.ACmp"
+ },
+ {
+ "id": "b",
+ "class": "com.yomahub.liteflow.test.endlessLoop.cmp.BCmp"
+ },
+ {
+ "id": "c",
+ "class": "com.yomahub.liteflow.test.endlessLoop.cmp.CCmp"
+ },
+ {
+ "id": "d",
+ "class": "com.yomahub.liteflow.test.endlessLoop.cmp.DCmp"
+ },
+ {
+ "id": "e",
+ "class": "com.yomahub.liteflow.test.endlessLoop.cmp.ECmp"
+ }
+ ]
+ },
+ "chain": [
+ {
+ "name": "chain7",
+ "value": "THEN(a, chain8);"
+ },
+ {
+ "name": "chain8",
+ "value": "THEN(b, chain9);"
+ },
+ {
+ "name": "chain9",
+ "value": "WHEN(c, chain7);"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow.el.xml
new file mode 100644
index 000000000..fdd72433d
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow.el.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+ THEN(a, chain2);
+
+
+
+ THEN(b, chain3);
+
+
+
+ THEN(c, chain1);
+
+
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow.el.yml b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow.el.yml
new file mode 100644
index 000000000..c82163e7c
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/endlessLoop/flow.el.yml
@@ -0,0 +1,20 @@
+flow:
+ nodes:
+ node:
+ - id: a
+ class: com.yomahub.liteflow.test.endlessLoop.cmp.ACmp
+ - id: b
+ class: com.yomahub.liteflow.test.endlessLoop.cmp.BCmp
+ - id: c
+ class: com.yomahub.liteflow.test.endlessLoop.cmp.CCmp
+ - id: d
+ class: com.yomahub.liteflow.test.endlessLoop.cmp.DCmp
+ - id: e
+ class: com.yomahub.liteflow.test.endlessLoop.cmp.ECmp
+ chain:
+ - name: chain4
+ value: "THEN(a, chain5);"
+ - name: chain5
+ value: "THEN(b, chain6);"
+ - name: chain6
+ value: "THEN(c, chain5);"
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowInDifferentConfigELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowInDifferentConfigELSpringbootTest.java
new file mode 100644
index 000000000..90efa473c
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowInDifferentConfigELSpringbootTest.java
@@ -0,0 +1,41 @@
+package com.yomahub.liteflow.test.endlessLoop;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.exception.CyclicDependencyException;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+
+import javax.annotation.Resource;
+
+/**
+ * 测试多文件情况下 chain 死循环逻辑
+ *
+ * @author luo yi
+ * @since 2.11.1
+ */
+@SpringBootTest(classes = FlowInDifferentConfigELSpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({ "com.yomahub.liteflow.test.endlessLoop.cmp"})
+public class FlowInDifferentConfigELSpringbootTest extends BaseTest {
+
+ @Resource
+ private FlowExecutor flowExecutor;
+
+ // 测试 chain 死循环
+ @Test
+ public void testChainEndlessLoop() {
+ Assertions.assertThrows(CyclicDependencyException.class, () -> {
+ LiteflowConfig config = LiteflowConfigGetter.get();
+ config.setRuleSource("endlessLoop/flow-sub1.el.xml,endlessLoop/flow-sub2.el.yml");
+ config.setSupportMultipleType(true);
+ flowExecutor.reloadRule();
+ });
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowJsonELSpringBootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowJsonELSpringBootTest.java
new file mode 100644
index 000000000..8bcb71cbf
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowJsonELSpringBootTest.java
@@ -0,0 +1,40 @@
+package com.yomahub.liteflow.test.endlessLoop;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.exception.CyclicDependencyException;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+
+import javax.annotation.Resource;
+
+/**
+ * 测试 json 文件情况下 chain 死循环逻辑
+ *
+ * @author luo yi
+ * @since 2.11.1
+ */
+@SpringBootTest(classes = FlowJsonELSpringBootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({ "com.yomahub.liteflow.test.endlessLoop.cmp" })
+public class FlowJsonELSpringBootTest extends BaseTest {
+
+ @Resource
+ private FlowExecutor flowExecutor;
+
+ // 测试 chain 死循环
+ @Test
+ public void testChainEndlessLoop() {
+ Assertions.assertThrows(CyclicDependencyException.class, () -> {
+ LiteflowConfig config = LiteflowConfigGetter.get();
+ config.setRuleSource("endlessLoop/flow.el.json");
+ flowExecutor.reloadRule();
+ });
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowXMLELSpringBootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowXMLELSpringBootTest.java
new file mode 100644
index 000000000..585cb02eb
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowXMLELSpringBootTest.java
@@ -0,0 +1,40 @@
+package com.yomahub.liteflow.test.endlessLoop;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.exception.CyclicDependencyException;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+
+import javax.annotation.Resource;
+
+/**
+ * 测试 xml 文件情况下 chain 死循环逻辑
+ *
+ * @author luo yi
+ * @since 2.11.1
+ */
+@SpringBootTest(classes = FlowXMLELSpringBootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({ "com.yomahub.liteflow.test.endlessLoop.cmp" })
+public class FlowXMLELSpringBootTest extends BaseTest {
+
+ @Resource
+ private FlowExecutor flowExecutor;
+
+ // 测试 chain 死循环
+ @Test
+ public void testChainEndlessLoop() {
+ Assertions.assertThrows(CyclicDependencyException.class, () -> {
+ LiteflowConfig config = LiteflowConfigGetter.get();
+ config.setRuleSource("endlessLoop/flow.el.xml");
+ flowExecutor.reloadRule();
+ });
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowYmlELSpringBootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowYmlELSpringBootTest.java
new file mode 100644
index 000000000..4df3d56db
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/FlowYmlELSpringBootTest.java
@@ -0,0 +1,40 @@
+package com.yomahub.liteflow.test.endlessLoop;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.exception.CyclicDependencyException;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+
+import javax.annotation.Resource;
+
+/**
+ * 测试 yml 文件情况下 chain 死循环逻辑
+ *
+ * @author luo yi
+ * @since 2.11.1
+ */
+@SpringBootTest(classes = FlowYmlELSpringBootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({ "com.yomahub.liteflow.test.endlessLoop.cmp" })
+public class FlowYmlELSpringBootTest extends BaseTest {
+
+ @Resource
+ private FlowExecutor flowExecutor;
+
+ // 测试 chain 死循环
+ @Test
+ public void testChainEndlessLoop() {
+ Assertions.assertThrows(CyclicDependencyException.class, () -> {
+ LiteflowConfig config = LiteflowConfigGetter.get();
+ config.setRuleSource("endlessLoop/flow.el.yml");
+ flowExecutor.reloadRule();
+ });
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ACmp.java
new file mode 100644
index 000000000..17c75c038
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ACmp.java
@@ -0,0 +1,14 @@
+package com.yomahub.liteflow.test.endlessLoop.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.stereotype.Component;
+
+@Component("a")
+public class ACmp extends NodeComponent {
+
+ @Override
+ public void process() {
+ System.out.println("Acomp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/BCmp.java
new file mode 100644
index 000000000..cdaa88716
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/BCmp.java
@@ -0,0 +1,14 @@
+package com.yomahub.liteflow.test.endlessLoop.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.stereotype.Component;
+
+@Component("b")
+public class BCmp extends NodeComponent {
+
+ @Override
+ public void process() {
+ System.out.println("Bcomp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/CCmp.java
new file mode 100644
index 000000000..7d9ec1ab6
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/CCmp.java
@@ -0,0 +1,14 @@
+package com.yomahub.liteflow.test.endlessLoop.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.stereotype.Component;
+
+@Component("c")
+public class CCmp extends NodeComponent {
+
+ @Override
+ public void process() throws Exception {
+ System.out.println("Ccomp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/DCmp.java
new file mode 100644
index 000000000..bf2f50f39
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/DCmp.java
@@ -0,0 +1,14 @@
+package com.yomahub.liteflow.test.endlessLoop.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.stereotype.Component;
+
+@Component("d")
+public class DCmp extends NodeComponent {
+
+ @Override
+ public void process() throws Exception {
+ System.out.println("Dcomp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ECmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ECmp.java
new file mode 100644
index 000000000..5a010ea22
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/endlessLoop/cmp/ECmp.java
@@ -0,0 +1,14 @@
+package com.yomahub.liteflow.test.endlessLoop.cmp;
+
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.stereotype.Component;
+
+@Component("e")
+public class ECmp extends NodeComponent {
+
+ @Override
+ public void process() throws Exception {
+ System.out.println("Ecomp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow-sub1.el.xml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow-sub1.el.xml
new file mode 100644
index 000000000..3f1a585ab
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow-sub1.el.xml
@@ -0,0 +1,6 @@
+
+
+
+ THEN(a, b);
+
+
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow-sub2.el.yml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow-sub2.el.yml
new file mode 100644
index 000000000..6861be3cc
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow-sub2.el.yml
@@ -0,0 +1,6 @@
+flow:
+ chain:
+ - name: chain2
+ value: "THEN(c, d, chain3);"
+ - name: chain3
+ value: "THEN(a, chain2);"
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow.el.json b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow.el.json
new file mode 100644
index 000000000..1a54d6c6c
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow.el.json
@@ -0,0 +1,18 @@
+{
+ "flow": {
+ "chain": [
+ {
+ "name": "chain7",
+ "value": "THEN(a, chain8);"
+ },
+ {
+ "name": "chain8",
+ "value": "THEN(b, chain9);"
+ },
+ {
+ "name": "chain9",
+ "value": "WHEN(c, chain7);"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow.el.xml
new file mode 100644
index 000000000..d615bf81d
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow.el.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ THEN(a, chain2);
+
+
+
+ THEN(b, chain3);
+
+
+
+ THEN(c, chain1);
+
+
+
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow.el.yml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow.el.yml
new file mode 100644
index 000000000..1699d501b
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/endlessLoop/flow.el.yml
@@ -0,0 +1,8 @@
+flow:
+ chain:
+ - name: chain4
+ value: "THEN(a, chain5);"
+ - name: chain5
+ value: "THEN(b, chain6);"
+ - name: chain6
+ value: "THEN(c, chain5);"
\ No newline at end of file