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 25493cd7d..b6193d455 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 @@ -81,10 +81,38 @@ public class Node implements Executable, Cloneable, Rollbackable{ private TransmittableThreadLocal accessResult = new TransmittableThreadLocal<>(); // 循环下标 - private TransmittableThreadLocal>> loopIndexTL = new TransmittableThreadLocal<>(); + private TransmittableThreadLocal> loopIndexTL = new TransmittableThreadLocal>() { + /** + * 在你提供的这个 TTL 版本中,我们重写 public T copy(T parentValue) 方法 + * 来实现 Stack 的克隆,以确保线程隔离。 + */ + @Override + public Stack copy(Stack parentValue) { + if (parentValue == null) { + return null; + } + // 克隆 Stack + return (Stack) parentValue.clone(); + } + }; + + // 迭代对象 - private TransmittableThreadLocal>> loopObjectTL = new TransmittableThreadLocal<>(); + private TransmittableThreadLocal> loopObjectTL = new TransmittableThreadLocal>() { + /** + * 在你提供的这个 TTL 版本中,我们重写 public T copy(T parentValue) 方法 + * 来实现 Stack 的克隆,以确保线程隔离。 + */ + @Override + public Stack copy(Stack parentValue) { + if (parentValue == null) { + return null; + } + // 克隆 Stack + return (Stack) parentValue.clone(); + } + }; // 当前slot的index private TransmittableThreadLocal slotIndexTL = new TransmittableThreadLocal<>(); @@ -355,19 +383,12 @@ public class Node implements Executable, Cloneable, Rollbackable{ try{ lock4LoopIndex.lock(); if (this.loopIndexTL.get() == null){ - Stack> stack = new Stack<>(); - TupleOf2 tuple = new TupleOf2<>(condition.hashCode(), index); - stack.push(tuple); + Stack stack = new Stack<>(); + stack.push(index); this.loopIndexTL.set(stack); }else{ - Stack> stack = this.loopIndexTL.get(); - TupleOf2 thisConditionTuple = stack.stream().filter(tuple -> tuple.getA().equals(condition.hashCode())).findFirst().orElse(null); - if (thisConditionTuple != null){ - thisConditionTuple.setB(index); - }else{ - TupleOf2 tuple = new TupleOf2<>(condition.hashCode(), index); - stack.push(tuple); - } + Stack stack = this.loopIndexTL.get(); + stack.push(index); } }finally { lock4LoopIndex.unlock(); @@ -376,9 +397,9 @@ public class Node implements Executable, Cloneable, Rollbackable{ } public Integer getLoopIndex() { - Stack> stack = this.loopIndexTL.get(); + Stack stack = this.loopIndexTL.get(); if (stack != null){ - return stack.peek().getB(); + return stack.peek(); }else{ return null; } @@ -389,9 +410,9 @@ public class Node implements Executable, Cloneable, Rollbackable{ } public Integer getPreNLoopIndex(int n){ - Stack> stack = this.loopIndexTL.get(); + Stack stack = this.loopIndexTL.get(); if (stack != null && stack.size() > n){ - return stack.elementAt(stack.size() - (n + 1)).getB(); + return stack.elementAt(stack.size() - (n + 1)); }else{ return null; } @@ -400,7 +421,7 @@ public class Node implements Executable, Cloneable, Rollbackable{ public void removeLoopIndex() { try{ lock4LoopIndex.lock(); - Stack> stack = this.loopIndexTL.get(); + Stack stack = this.loopIndexTL.get(); if (stack != null){ if (stack.size() > 1){ stack.pop(); @@ -420,19 +441,12 @@ public class Node implements Executable, Cloneable, Rollbackable{ try{ lock4LoopObj.lock(); if (this.loopObjectTL.get() == null){ - Stack> stack = new Stack<>(); - TupleOf2 tuple = new TupleOf2<>(condition.hashCode(), obj); - stack.push(tuple); + Stack stack = new Stack<>(); + stack.push(obj); this.loopObjectTL.set(stack); }else{ - Stack> stack = this.loopObjectTL.get(); - TupleOf2 thisConditionTuple = stack.stream().filter(tuple -> tuple.getA().equals(condition.hashCode())).findFirst().orElse(null); - if (thisConditionTuple != null){ - thisConditionTuple.setB(obj); - }else{ - TupleOf2 tuple = new TupleOf2<>(condition.hashCode(), obj); - stack.push(tuple); - } + Stack stack = this.loopObjectTL.get(); + stack.push(obj); } }finally { lock4LoopObj.unlock(); @@ -440,9 +454,9 @@ public class Node implements Executable, Cloneable, Rollbackable{ } public T getCurrLoopObject() { - Stack> stack = this.loopObjectTL.get(); + Stack stack = this.loopObjectTL.get(); if (stack != null){ - return (T) stack.peek().getB(); + return (T) stack.peek(); }else{ return null; } @@ -453,9 +467,9 @@ public class Node implements Executable, Cloneable, Rollbackable{ } public T getPreNLoopObject(int n){ - Stack> stack = this.loopObjectTL.get(); + Stack stack = this.loopObjectTL.get(); if (stack != null && stack.size() > n){ - return (T) stack.elementAt(stack.size() - (n + 1)).getB(); + return (T) stack.elementAt(stack.size() - (n + 1)); }else{ return null; } @@ -464,7 +478,7 @@ public class Node implements Executable, Cloneable, Rollbackable{ public void removeCurrLoopObject() { try{ lock4LoopObj.lock(); - Stack> stack = this.loopObjectTL.get(); + Stack stack = this.loopObjectTL.get(); if (stack != null){ if (stack.size() > 1){ stack.pop(); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java index 6ebcb0a87..b427241cf 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/IteratorCondition.java @@ -87,8 +87,7 @@ public class IteratorCondition extends LoopCondition { //存储所有的并行执行子项的CompletableFuture List> futureList = new ArrayList<>(); //获取并行循环的线程池 - ExecutorService parallelExecutor = ExecutorHelper.loadInstance().buildExecutorService(this, slotIndex - , this.getConditionType()); + ExecutorService parallelExecutor = ExecutorHelper.loadInstance().buildExecutorService(this, slotIndex , this.getConditionType()); while (it.hasNext()) { Object itObj = it.next(); //提交异步任务 diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/util/TupleOf2.java b/liteflow-core/src/main/java/com/yomahub/liteflow/util/TupleOf2.java index 3a9730205..c965c66f4 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/util/TupleOf2.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/util/TupleOf2.java @@ -1,6 +1,6 @@ package com.yomahub.liteflow.util; -public class TupleOf2 { +public class TupleOf2 implements Cloneable{ private A a; @@ -26,4 +26,13 @@ public class TupleOf2 { public void setB(B b) { this.b = b; } + + @Override + @SuppressWarnings("unchecked") + public TupleOf2 clone() throws CloneNotSupportedException { + TupleOf2 newObject = (TupleOf2)super.clone(); + newObject.setA(this.getA()); + newObject.setB(this.getB()); + return newObject; + } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringbootTest.java index 3bbb52f8c..b2fcc5437 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringbootTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/IteratorELSpringbootTest.java @@ -12,7 +12,9 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.ComponentScan; import org.springframework.test.context.TestPropertySource; import javax.annotation.Resource; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * springboot环境EL常规的例子测试 @@ -72,9 +74,13 @@ public class IteratorELSpringbootTest extends BaseTest { //测试多层迭代异步循环的正确性 @Test public void testIt5() throws Exception { - for (int i = 0; i < 100; i++) { - LiteflowResponse response = flowExecutor.execute2Resp("chain5"); - Assertions.assertTrue(response.isSuccess()); - } + DefaultContext context = new DefaultContext(); + context.setData("set", new HashSet<>()); + context.setData("list1", ListUtil.toList("a", "b", "c")); + context.setData("list2", ListUtil.toList("1", "2", "3", "4")); + LiteflowResponse response = flowExecutor.execute2Resp("chain5",null, context); + Assertions.assertTrue(response.isSuccess()); + Set set = context.getData("set"); + Assertions.assertEquals(12, set.size()); } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/FCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/FCmp.java index 570973b93..10f62bb74 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/FCmp.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/FCmp.java @@ -6,6 +6,8 @@ import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.slot.DefaultContext; import org.springframework.stereotype.Component; +import java.util.Set; + @Component("f") public class FCmp extends NodeComponent { @@ -16,6 +18,9 @@ public class FCmp extends NodeComponent { if (obj1 == null || obj2 == null) { throw new RuntimeException(""); } - System.out.println(StrUtil.format("{}{}", obj1, obj2)); + String str = StrUtil.format("{}{}", obj1, obj2); + DefaultContext context = this.getFirstContextBean(); + Set set = context.getData("set"); + set.add(str); } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X1Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X1Cmp.java index 361eabb78..2f270ee49 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X1Cmp.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X1Cmp.java @@ -3,6 +3,7 @@ package com.yomahub.liteflow.test.iterator.cmp; import cn.hutool.core.collection.ListUtil; import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeIteratorComponent; +import com.yomahub.liteflow.slot.DefaultContext; import java.util.Iterator; import java.util.List; @@ -11,7 +12,8 @@ import java.util.List; public class X1Cmp extends NodeIteratorComponent { @Override public Iterator processIterator() throws Exception { - List list = ListUtil.toList("a", "b", "c"); + DefaultContext context = this.getFirstContextBean(); + List list = context.getData("list1"); return list.iterator(); } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X2Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X2Cmp.java index 0c07eaab3..6e6320960 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X2Cmp.java +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/iterator/cmp/X2Cmp.java @@ -3,6 +3,7 @@ package com.yomahub.liteflow.test.iterator.cmp; import cn.hutool.core.collection.ListUtil; import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeIteratorComponent; +import com.yomahub.liteflow.slot.DefaultContext; import java.util.Iterator; import java.util.List; @@ -11,7 +12,8 @@ import java.util.List; public class X2Cmp extends NodeIteratorComponent { @Override public Iterator processIterator() throws Exception { - List list = ListUtil.toList("11", "22"); + DefaultContext context = this.getFirstContextBean(); + List list = context.getData("list2"); return list.iterator(); } } diff --git a/pom.xml b/pom.xml index 859a6e788..d14ba8525 100644 --- a/pom.xml +++ b/pom.xml @@ -53,7 +53,7 @@ 5.3.0 5.8.2 5.8.26 - 2.12.3 + 2.14.5 5.1.0 0.10 0.7.3