浏览代码

feature #I54VBS 从设计上改善NodeComponent,使之变成声明式的组件

bryan31 3 年之前
父节点
当前提交
935506a388
共有 100 个文件被更改,包括 3368 次插入12 次删除
  1. 4 0
      liteflow-core/pom.xml
  2. 10 0
      liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowCmpDefine.java
  3. 10 0
      liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowCondCmpDefine.java
  4. 14 0
      liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowMethod.java
  5. 1 0
      liteflow-core/src/main/java/com/yomahub/liteflow/annotation/util/AnnoUtil.java
  6. 6 0
      liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java
  7. 1 1
      liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java
  8. 129 0
      liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ComponentProxy.java
  9. 31 0
      liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/LiteFlowMethodBean.java
  10. 26 0
      liteflow-core/src/main/java/com/yomahub/liteflow/enums/LiteFlowMethodEnum.java
  11. 22 0
      liteflow-core/src/main/java/com/yomahub/liteflow/exception/ComponentMethodDefineErrorException.java
  12. 22 0
      liteflow-core/src/main/java/com/yomahub/liteflow/exception/ComponentProxyErrorException.java
  13. 37 11
      liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java
  14. 2 0
      liteflow-core/src/main/java/com/yomahub/liteflow/spi/ContextAware.java
  15. 5 0
      liteflow-core/src/main/java/com/yomahub/liteflow/spi/local/LocalContextAware.java
  16. 102 0
      liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteFlowProxyUtil.java
  17. 192 0
      liteflow-core/src/main/java/com/yomahub/liteflow/util/SerialsUtil.java
  18. 10 0
      liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringAware.java
  19. 13 0
      liteflow-spring/src/main/java/com/yomahub/liteflow/spring/ComponentScanner.java
  20. 69 0
      liteflow-testcase-declare-component/pom.xml
  21. 20 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/BaseTest.java
  22. 42 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathSpringbootTest.java
  23. 24 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/ACmp.java
  24. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/BCmp.java
  25. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/CCmp.java
  26. 56 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/CustomAOPSpringbootTest.java
  27. 76 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/GlobalAOPSpringbootTest.java
  28. 17 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/aspect/CmpAspect.java
  29. 27 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/aspect/CustomAspect.java
  30. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp1/ACmp.java
  31. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp1/BCmp.java
  32. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp1/CCmp.java
  33. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp2/DCmp.java
  34. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp2/ECmp.java
  35. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp2/FCmp.java
  36. 134 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/AsyncNodeSpringbootTest.java
  37. 28 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ACmp.java
  38. 28 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/BCmp.java
  39. 28 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/CCmp.java
  40. 29 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/DCmp.java
  41. 20 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ECmp.java
  42. 18 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/FCmp.java
  43. 30 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/GCmp.java
  44. 30 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/HCmp.java
  45. 28 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ICmp.java
  46. 21 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/JCmp.java
  47. 4 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/exception/TestException.java
  48. 39 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/BaseSpringbootTest.java
  49. 24 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/cmp/ACmp.java
  50. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/cmp/BCmp.java
  51. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/cmp/CCmp.java
  52. 31 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/cmp/DCmp.java
  53. 10 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/cmp/TestDomain.java
  54. 217 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/BuilderSpringbootTest1.java
  55. 41 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/BuilderSpringbootTest2.java
  56. 22 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ACmp.java
  57. 23 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/BCmp.java
  58. 23 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/CCmp.java
  59. 23 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/DCmp.java
  60. 24 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ECmp.java
  61. 23 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/FCmp.java
  62. 23 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/GCmp.java
  63. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp2/HCmp.java
  64. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp2/ICmp.java
  65. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp2/JCmp.java
  66. 64 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/LiteflowRetrySpringbootTest.java
  67. 24 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ACmp.java
  68. 31 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/BCmp.java
  69. 28 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/CCmp.java
  70. 28 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/DCmp.java
  71. 28 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ECmp.java
  72. 94 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/FlowExecutorSpringbootTest.java
  73. 30 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/ACmp.java
  74. 33 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/BCmp.java
  75. 33 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/CCmp.java
  76. 30 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/DCmp.java
  77. 28 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/ECmp.java
  78. 30 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/GCmp.java
  79. 24 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/HCmp.java
  80. 27 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp2/FCondCmp.java
  81. 45 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/CustomNodesSpringbootTest.java
  82. 22 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ACmp.java
  83. 29 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/BCmp.java
  84. 23 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/CCmp.java
  85. 23 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/DCmp.java
  86. 30 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ECmp.java
  87. 23 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/FCmp.java
  88. 11 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/domain/DemoDomain.java
  89. 25 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor1.java
  90. 24 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor2.java
  91. 24 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor3.java
  92. 72 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomWhenThreadPoolSpringbootTest.java
  93. 24 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ACmp.java
  94. 26 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/BCmp.java
  95. 26 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/CCmp.java
  96. 26 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/DCmp.java
  97. 26 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ECmp.java
  98. 26 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/FCmp.java
  99. 83 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/exception/ExceptionSpringBootTest.java
  100. 34 0
      liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/exception/cmp/ACmp.java

+ 4 - 0
liteflow-core/pom.xml

@@ -61,5 +61,9 @@
 			<groupId>com.alibaba</groupId>
 			<artifactId>transmittable-thread-local</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>net.bytebuddy</groupId>
+			<artifactId>byte-buddy</artifactId>
+		</dependency>
 	</dependencies>
 </project>

+ 10 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowCmpDefine.java

@@ -0,0 +1,10 @@
+package com.yomahub.liteflow.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface LiteflowCmpDefine {
+}

+ 10 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowCondCmpDefine.java

@@ -0,0 +1,10 @@
+package com.yomahub.liteflow.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface LiteflowCondCmpDefine {
+}

+ 14 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/annotation/LiteflowMethod.java

@@ -0,0 +1,14 @@
+package com.yomahub.liteflow.annotation;
+
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface LiteflowMethod {
+
+    LiteFlowMethodEnum value();
+}

+ 1 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/annotation/util/AnnoUtil.java

@@ -4,6 +4,7 @@ import cn.hutool.core.annotation.AnnotationUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ReflectUtil;
 import com.yomahub.liteflow.annotation.AliasFor;
+import com.yomahub.liteflow.util.LiteFlowProxyUtil;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;

+ 6 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java

@@ -64,6 +64,12 @@ public class LiteFlowNodeBuilder {
         return this;
     }
 
+    public LiteFlowNodeBuilder setClazz(Class<?> clazz){
+        assert clazz != null;
+        setClazz(clazz.getName());
+        return this;
+    }
+
     // 设置节点组件的class
     public LiteFlowNodeBuilder setNodeComponentClazz(Class<? extends NodeComponent> nodeComponentClass) {
         assert nodeComponentClass != null;

+ 1 - 1
liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java

@@ -35,7 +35,7 @@ import java.util.Map;
  */
 public abstract class NodeComponent{
 
-	private static final Logger LOG = LoggerFactory.getLogger(NodeComponent.class);
+	private final Logger LOG = LoggerFactory.getLogger(this.getClass());
 
 	private final TransmittableThreadLocal<Integer> slotIndexTL = new TransmittableThreadLocal<>();
 

+ 129 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/ComponentProxy.java

@@ -0,0 +1,129 @@
+package com.yomahub.liteflow.core.proxy;
+
+import cn.hutool.core.util.*;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.exception.ComponentMethodDefineErrorException;
+import com.yomahub.liteflow.util.LiteFlowProxyUtil;
+import com.yomahub.liteflow.util.SerialsUtil;
+import net.bytebuddy.ByteBuddy;
+import net.bytebuddy.implementation.InvocationHandlerAdapter;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 声明式组件的代理核心生成类
+ * @author Bryan.Zhang
+ * @since 2.6.14
+ */
+public class ComponentProxy {
+
+    private final Logger LOG = LoggerFactory.getLogger(this.getClass());
+
+    private final String nodeId;
+
+    private final Object bean;
+
+    private final Class<?> clazz;
+
+    public ComponentProxy(String nodeId, Object bean, Class<?> clazz) {
+        this.nodeId = nodeId;
+        this.bean = bean;
+        this.clazz = clazz;
+    }
+
+    public Object getProxy() throws Exception{
+        //这里要判断bean是否是spring代理过的bean,如果是代理过的bean需要取到原class对象
+        Class<?> beanClazz;
+        if (LiteFlowProxyUtil.isCglibProxyClass(bean.getClass())){
+            beanClazz = LiteFlowProxyUtil.getUserClass(bean.getClass());
+        }else{
+            beanClazz = bean.getClass();
+        }
+
+        //得到当前bean里所覆盖的组件方法(一定是被@LiteFlowMethod修饰的),自己定义的不算
+        List<String> methodStrList = Arrays.stream(beanClazz.getDeclaredMethods()).filter(
+                m -> m.getAnnotation(LiteflowMethod.class) != null
+        ).map(m -> {
+            LiteflowMethod liteflowMethod = m.getAnnotation(LiteflowMethod.class);
+            return liteflowMethod.value().getMethodName();
+        }).collect(Collectors.toList());
+
+        //创建对象
+        //这里package进行了重设,放到了被代理对象的所在目录
+        //生成的对象也加了上被代理对象拥有的注解
+        //被拦截的对象也根据被代理对象根据@LiteFlowMethod所标注的进行了动态判断
+        return new ByteBuddy().subclass(clazz)
+                .name(StrUtil.format("{}.ByteBuddy${}${}",
+                        ClassUtil.getPackage(bean.getClass()),
+                        nodeId,
+                        SerialsUtil.generateShortUUID()))
+                .method(ElementMatchers.namedOneOf(methodStrList.toArray(new String[]{})))
+                .intercept(InvocationHandlerAdapter.of(new AopInvocationHandler(bean)))
+                .annotateType(bean.getClass().getAnnotations())
+                .make()
+                .load(ComponentProxy.class.getClassLoader())
+                .getLoaded()
+                .newInstance();
+    }
+
+    public class AopInvocationHandler implements InvocationHandler {
+
+        private final Object bean;
+
+        public AopInvocationHandler(Object bean) {
+            this.bean = bean;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            //这里做了2件事情
+            //先是从普通的bean里过滤出含有@LiteFlowMethod这个标注的方法
+            //然后进行转换成LiteFlowMethodBean对象List,形成<methodName,Method>键值对的对象
+            List<LiteFlowMethodBean> liteFlowMethodBeanList = Arrays.stream(ReflectUtil.getMethods(bean.getClass())).filter(m -> {
+                LiteflowMethod liteFlowMethod = m.getAnnotation(LiteflowMethod.class);
+                return ObjectUtil.isNotNull(liteFlowMethod);
+            }).map(m -> {
+                LiteflowMethod liteFlowMethod = m.getAnnotation(LiteflowMethod.class);
+                return new LiteFlowMethodBean(liteFlowMethod.value().getMethodName(), m);
+            }).collect(Collectors.toList());
+
+            //获取当前调用方法,是否在被代理的对象方法里面(根据@LiteFlowMethod这个标注去判断)
+            //如果在里面,则返回那个LiteFlowMethodBean,不在则返回null
+            LiteFlowMethodBean liteFlowMethodBean = liteFlowMethodBeanList.stream().filter(
+                    liteFlowMethodBean1 -> liteFlowMethodBean1.getMethod().getName().equals(method.getName())
+            ).findFirst().orElse(null);
+
+            //如果被代理的对象里有此标注标的方法,则调用此被代理的对象里的方法,如果没有,则调用父类里的方法
+            if (liteFlowMethodBean != null){
+                //进行检查,检查被代理的bean里是否有且仅有NodeComponent这个类型的参数
+                boolean checkFlag = liteFlowMethodBean.getMethod().getParameterTypes().length == 1
+                        && Arrays.asList(liteFlowMethodBean.getMethod().getParameterTypes()).contains(NodeComponent.class);
+                if (!checkFlag){
+                    String errMsg = StrUtil.format("Method[{}.{}] must have NodeComponent parameter(and only one parameter)", bean.getClass().getName(), liteFlowMethodBean.getMethod().getName());
+                    LOG.error(errMsg);
+                    throw new ComponentMethodDefineErrorException(errMsg);
+                }
+
+                try{
+                    return liteFlowMethodBean.getMethod().invoke(bean, proxy);
+                }catch (Exception e){
+                    InvocationTargetException targetEx = (InvocationTargetException)e;
+                    throw targetEx.getTargetException();
+                }
+            }else{
+                //理论上来说这句应该执行不到,因为前面在设置拦截对象类型的时候,已经根据当前bean所覆盖的方法进行了动态判断
+                return method.invoke(proxy, args);
+            }
+        }
+    }
+}

+ 31 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/core/proxy/LiteFlowMethodBean.java

@@ -0,0 +1,31 @@
+package com.yomahub.liteflow.core.proxy;
+
+import java.lang.reflect.Method;
+
+public class LiteFlowMethodBean {
+
+    private String methodName;
+
+    private Method method;
+
+    public LiteFlowMethodBean(String methodName, Method method) {
+        this.methodName = methodName;
+        this.method = method;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public void setMethodName(String methodName) {
+        this.methodName = methodName;
+    }
+
+    public Method getMethod() {
+        return method;
+    }
+
+    public void setMethod(Method method) {
+        this.method = method;
+    }
+}

+ 26 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/enums/LiteFlowMethodEnum.java

@@ -0,0 +1,26 @@
+package com.yomahub.liteflow.enums;
+
+public enum LiteFlowMethodEnum {
+    PROCESS("process"),
+    PROCESS_COND("processCond"),
+    IS_ACCESS("isAccess"),
+
+    IS_END("isEnd"),
+    IS_CONTINUE_ON_ERROR("isContinueOnError"),
+
+    GET_NODE_EXECUTOR_CLASS("getNodeExecutorClass");
+
+    private String methodName;
+
+    LiteFlowMethodEnum(String methodName){
+        this.methodName = methodName;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public void setMethodName(String methodName) {
+        this.methodName = methodName;
+    }
+}

+ 22 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/exception/ComponentMethodDefineErrorException.java

@@ -0,0 +1,22 @@
+
+package com.yomahub.liteflow.exception;
+
+public class ComponentMethodDefineErrorException extends RuntimeException {
+
+	private static final long serialVersionUID = 1L;
+
+	/** 异常信息 */
+	private String message;
+
+	public ComponentMethodDefineErrorException(String message) {
+		this.message = message;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public void setMessage(String message) {
+		this.message = message;
+	}
+}

+ 22 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/exception/ComponentProxyErrorException.java

@@ -0,0 +1,22 @@
+
+package com.yomahub.liteflow.exception;
+
+public class ComponentProxyErrorException extends RuntimeException {
+
+	private static final long serialVersionUID = 1L;
+
+	/** 异常信息 */
+	private String message;
+
+	public ComponentProxyErrorException(String message) {
+		this.message = message;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public void setMessage(String message) {
+		this.message = message;
+	}
+}

+ 37 - 11
liteflow-core/src/main/java/com/yomahub/liteflow/flow/FlowBus.java

@@ -28,8 +28,11 @@ import com.yomahub.liteflow.parser.LocalYmlFlowParser;
 import com.yomahub.liteflow.script.ScriptExecutor;
 import com.yomahub.liteflow.script.ScriptExecutorFactory;
 import com.yomahub.liteflow.script.exception.ScriptSpiException;
+import com.yomahub.liteflow.spi.ContextAware;
 import com.yomahub.liteflow.spi.holder.ContextAwareHolder;
+import com.yomahub.liteflow.spi.local.LocalContextAware;
 import com.yomahub.liteflow.util.CopyOnWriteHashMap;
+import com.yomahub.liteflow.util.LiteFlowProxyUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -82,8 +85,13 @@ public class FlowBus {
         nodeMap.put(nodeId, new Node(ComponentInitializer.loadInstance().initComponent(nodeComponent, NodeTypeEnum.COMMON, null, nodeId)));
     }
 
-    public static void addCommonNode(String nodeId, String name, String cmpClazzStr) throws Exception {
-        Class<NodeComponent> cmpClazz = (Class<NodeComponent>) Class.forName(cmpClazzStr);
+    public static void addCommonNode(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.COMMON, cmpClazz, null);
     }
 
@@ -99,18 +107,36 @@ public class FlowBus {
         addNode(nodeId, name, NodeTypeEnum.COND_SCRIPT, ScriptCondComponent.class, script);
     }
 
-    private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<? extends NodeComponent> cmpClazz, String script) {
+    private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz, String script) {
         try {
-            //以node方式配置,本质上是为了适配无spring的环境,如果有spring环境,其实不用这么配置
-            //这里的逻辑是判断是否能从spring上下文中取到,如果没有spring,则就是new instance了
-            //如果是script类型的节点,因为class只有一个,所以也不能注册进spring上下文,注册的时候需要new Instance
+            //判断此类是否是声明式的组件,如果是声明式的组件,就用动态代理生成实例
+            //如果不是声明式的,就用传统的方式进行判断
             NodeComponent cmpInstance = null;
-            if (!CollectionUtil.newArrayList(NodeTypeEnum.SCRIPT, NodeTypeEnum.COND_SCRIPT).contains(type)){
-                cmpInstance = ContextAwareHolder.loadContextAware().registerOrGet(nodeId, cmpClazz);
-            }
+            if (LiteFlowProxyUtil.isMarkedCmp(cmpClazz)){
+                //这里的逻辑要仔细看下
+                //如果是spring体系,把原始的类往spring上下文中进行注册,那么会走到ComponentScanner中
+                //由于ComponentScanner中已经对原始类进行了动态代理,出来的对象已经变成了动态代理类,所以这时候的bean已经是NodeComponent的子类了
+                //所以spring体系下,无需再对这个bean做二次代理
+                //但是在非spring体系下,这个bean依旧是原来那个bean,所以需要对这个bean做一次代理
+                //这里用ContextAware的spi机制来判断是否spring体系
+                ContextAware contextAware = ContextAwareHolder.loadContextAware();
+                Object bean = ContextAwareHolder.loadContextAware().registerBean(nodeId, cmpClazz);
+                if (LocalContextAware.class.isAssignableFrom(contextAware.getClass())){
+                    cmpInstance = LiteFlowProxyUtil.proxy2NodeComponent(bean, nodeId);
+                }else {
+                    cmpInstance = (NodeComponent) bean;
+                }
+            }else{
+                //以node方式配置,本质上是为了适配无spring的环境,如果有spring环境,其实不用这么配置
+                //这里的逻辑是判断是否能从spring上下文中取到,如果没有spring,则就是new instance了
+                //如果是script类型的节点,因为class只有一个,所以也不能注册进spring上下文,注册的时候需要new Instance
+                if (!CollectionUtil.newArrayList(NodeTypeEnum.SCRIPT, NodeTypeEnum.COND_SCRIPT).contains(type)){
+                    cmpInstance = (NodeComponent) ContextAwareHolder.loadContextAware().registerOrGet(nodeId, cmpClazz);
+                }
 
-            if (ObjectUtil.isNull(cmpInstance)) {
-                cmpInstance = cmpClazz.newInstance();
+                if (ObjectUtil.isNull(cmpInstance)) {
+                    cmpInstance = (NodeComponent) cmpClazz.newInstance();
+                }
             }
 
             //进行初始化

+ 2 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/spi/ContextAware.java

@@ -16,5 +16,7 @@ public interface ContextAware extends SpiPriority {
 
     <T> T registerBean(Class<T> clazz);
 
+    <T> T registerBean(String beanName, Object bean);
+
     <T> T registerOrGet(String beanName, Class<T> clazz);
 }

+ 5 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/spi/local/LocalContextAware.java

@@ -30,6 +30,11 @@ public class LocalContextAware implements ContextAware {
         return registerBean(null, clazz);
     }
 
+    @Override
+    public <T> T registerBean(String beanName, Object bean) {
+        return (T)bean;
+    }
+
     @Override
     public <T> T registerOrGet(String beanName, Class<T> clazz) {
         return registerBean(beanName, clazz);

+ 102 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteFlowProxyUtil.java

@@ -0,0 +1,102 @@
+package com.yomahub.liteflow.util;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowCondCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.core.NodeCondComponent;
+import com.yomahub.liteflow.core.proxy.ComponentProxy;
+import com.yomahub.liteflow.exception.ComponentProxyErrorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Arrays;
+
+/**
+ * 组件代理类通用方法
+ * 主要用于声明式组件
+ * @author Bryan.Zhang
+ * @since 2.6.14
+ */
+public class LiteFlowProxyUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LiteFlowProxyUtil.class);
+
+    //判断一个bean是否是解耦式组件
+    public static boolean isMarkedCmp(Class<?> clazz){
+        //判断bean是否标记了@LiteflowCmpDefine或者@LiteflowCondCmpDefine这2个标注之一
+        boolean flag1 = clazz.getAnnotation(LiteflowCmpDefine.class) != null
+                || clazz.getAnnotation(LiteflowCondCmpDefine.class) != null;
+
+        if (!flag1){
+            return false;
+        }
+
+        //看超类是否是NodeComponent和NodeCondComponent中的一个,如果不是,则说明满足条件。是的话,也不满足
+        boolean flag2 = !ListUtil.toList(NodeComponent.class, NodeCondComponent.class).contains(clazz.getSuperclass());
+
+        if (!flag2){
+            return false;
+        }
+
+        //查看bean里的method是否有方法标记了@LiteflowMethod标注
+        //这里的bean有可能是cglib加强过的class,所以要先进行个判断
+        Class<?> targetClass;
+        if (isCglibProxyClass(clazz)){
+            targetClass = getUserClass(clazz);
+        }else{
+            targetClass = clazz;
+        }
+        boolean flag3 = Arrays.stream(targetClass.getMethods()).anyMatch(
+                method -> method.getAnnotation(LiteflowMethod.class) != null
+        );
+
+        return flag3;
+    }
+
+    //对一个满足声明式的bean进行代理
+    public static NodeComponent proxy2NodeComponent(Object bean, String nodeId){
+        try{
+            LiteflowCmpDefine liteflowCmpDefine = bean.getClass().getAnnotation(LiteflowCmpDefine.class);
+            LiteflowCondCmpDefine liteflowCondCmpDefine = bean.getClass().getAnnotation(LiteflowCondCmpDefine.class);
+
+            ComponentProxy proxy;
+            if (ObjectUtil.isNotNull(liteflowCmpDefine)){
+                proxy = new ComponentProxy(nodeId, bean, NodeComponent.class);
+                return (NodeComponent) proxy.getProxy();
+            }
+
+            if (ObjectUtil.isNotNull(liteflowCondCmpDefine)){
+                proxy = new ComponentProxy(nodeId, bean, NodeCondComponent.class);
+                return (NodeCondComponent) proxy.getProxy();
+            }
+
+            throw new RuntimeException();
+        }catch (Exception e){
+            String errMsg = StrUtil.format("Error while proxying bean[{}]",bean.getClass().getName());
+            LOG.error(errMsg, e);
+            throw new ComponentProxyErrorException(errMsg);
+        }
+    }
+
+    public static boolean isCglibProxyClass(Class<?> clazz) {
+        return (clazz != null && isCglibProxyClassName(clazz.getName()));
+    }
+
+    public static Class<?> getUserClass(Class<?> clazz) {
+        if (clazz.getName().contains("$$")) {
+            Class<?> superclass = clazz.getSuperclass();
+            if (superclass != null && superclass != Object.class) {
+                return superclass;
+            }
+        }
+        return clazz;
+    }
+
+    private static boolean isCglibProxyClassName(String className) {
+        return (className != null && className.contains("$$"));
+    }
+}

+ 192 - 0
liteflow-core/src/main/java/com/yomahub/liteflow/util/SerialsUtil.java

@@ -0,0 +1,192 @@
+package com.yomahub.liteflow.util;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class SerialsUtil {
+
+    public static int serialInt = 1;
+
+    private static final DecimalFormat format8 = new DecimalFormat("00000000");
+    private static final DecimalFormat format12 = new DecimalFormat("000000000000");
+    private static final BigInteger divisor;
+    private static final BigInteger divisor12;
+
+    static {
+        divisor = BigInteger.valueOf(19999999L).multiply(BigInteger.valueOf(5));
+        divisor12 = BigInteger.valueOf(190000000097L).multiply(BigInteger.valueOf(5));
+    }
+
+    public static String genSerialNo(){
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+        String strNow = sdf.format(new Date());
+
+        // 生成3位随机数
+        Random random = new Random();
+        int intRandom = random.nextInt(999);
+
+        String strRandom = String.valueOf(intRandom);
+        int len = strRandom.length();
+        for (int i = 0; i < (3-len); i++) {
+            strRandom = "0" + strRandom;
+        }
+        String serialStr = SerialsUtil.nextSerial();
+        return (strNow + strRandom + serialStr) ;
+    }
+
+    public static synchronized String nextSerial(){
+        int serial = serialInt++;
+        if (serial > 999){
+            serialInt = 1;
+            serial=1;
+        }
+        String serialStr = serial + "";
+        int len = serialStr.length();
+        for (int i = 0; i < (3-len); i++) {
+            serialStr = "0" + serialStr;
+        }
+
+        return serialStr;
+    }
+
+
+    /**
+     * 生成一个12位随机数
+     *
+     * @param seed 种子
+     * @return
+     */
+    public static String randomNum12(long seed) {
+        // 被除数
+        BigInteger dividend = BigDecimal.valueOf(seed).pow(5).toBigInteger();
+        return format12.format(dividend.remainder(divisor12));
+    }
+
+    /**
+     * 生成一个8位随机数
+     *
+     * @param seed 种子
+     * @return
+     */
+    public static String randomNum8(long seed) {
+        // 被除数
+        BigInteger dividend = BigDecimal.valueOf(seed).pow(5).toBigInteger();
+        return format8.format(dividend.remainder(divisor));
+    }
+
+    /*
+     * 10进制转32进制(去除0,O,1,I)
+     */
+    public static String from10To32(String numStr, int size){
+        long to=32;
+        long num = Long.parseLong(numStr);
+        String jg="";
+        while(num!=0){
+            switch (new Long(num%to).intValue()) {
+                case 0:jg="B"+jg;break; case 1:jg="R"+jg;break; case 2:jg="6"+jg;break; case 3:jg="U"+jg;break;
+                case 4:jg="M"+jg;break; case 5:jg="E"+jg;break; case 6:jg="H"+jg;break; case 7:jg="C"+jg;break;
+                case 8:jg="G"+jg;break; case 9:jg="Q"+jg;break; case 10:jg="A"+jg;break; case 11:jg="8"+jg;break;
+                case 12:jg="3"+jg;break; case 13:jg="S"+jg;break; case 14:jg="J"+jg;break; case 15:jg="Y"+jg;break;
+                case 16:jg="7"+jg;break; case 17:jg="5"+jg;break; case 18:jg="W"+jg;break; case 19:jg="9"+jg;break;
+                case 20:jg="F"+jg;break; case 21:jg="T"+jg;break; case 22:jg="D"+jg;break; case 23:jg="2"+jg;break;
+                case 24:jg="P"+jg;break; case 25:jg="Z"+jg;break; case 26:jg="N"+jg;break; case 27:jg="K"+jg;break;
+                case 28:jg="V"+jg;break; case 29:jg="X"+jg;break; case 30:jg="L"+jg;break; case 31:jg="4"+jg;break;
+                default: jg=String.valueOf(num%to)+jg;break;
+            }
+            num=num/to;
+        }
+        if (jg.length() < size){
+            int loop = size - jg.length();
+            for (int i = 0; i < loop; i++){
+                jg = "2" + jg;
+            }
+        }
+        return jg;
+    }
+
+    /*
+     * 10进制转32进制(去除0,O,1,I)
+     */
+    public static String from10To24(String numStr, int size){
+        long to=24;
+        long num = Long.parseLong(numStr);
+        String jg="";
+        while(num!=0){
+            switch (new Long(num%to).intValue()) {
+                case 0:jg="B"+jg;break;
+                case 1:jg="R"+jg;break;
+                case 2:jg="U"+jg;break;
+                case 3:jg="M"+jg;break;
+                case 4:jg="E"+jg;break;
+                case 5:jg="H"+jg;break;
+                case 6:jg="C"+jg;break;
+                case 7:jg="G"+jg;break;
+                case 8:jg="Q"+jg;break;
+                case 9:jg="A"+jg;break;
+                case 10:jg="S"+jg;break;
+                case 11:jg="J"+jg;break;
+                case 12:jg="Y"+jg;break;
+                case 13:jg="W"+jg;break;
+                case 14:jg="F"+jg;break;
+                case 15:jg="T"+jg;break;
+                case 16:jg="D"+jg;break;
+                case 17:jg="P"+jg;break;
+                case 18:jg="Z"+jg;break;
+                case 19:jg="N"+jg;break;
+                case 20:jg="K"+jg;break;
+                case 21:jg="V"+jg;break;
+                case 22:jg="X"+jg;break;
+                case 23:jg="L"+jg;break;
+                default: jg=String.valueOf(num%to)+jg;break;
+            }
+            num=num/to;
+        }
+        if (jg.length() < size){
+            int loop = size - jg.length();
+            for (int i = 0; i < loop; i++){
+                jg = "B" + jg;
+            }
+        }
+        return jg;
+    }
+
+    /**
+     * 32位
+     * @return
+     */
+    public static String getUUID() {
+        UUID uuid = UUID.randomUUID();
+        String str = uuid.toString();
+        // 去掉"-"符号
+        String temp = str.substring(0, 8) + str.substring(9, 13) + str.substring(14, 18) + str.substring(19, 23) + str.substring(24);
+        return temp;
+    }
+
+    public static String generateShortUUID() {
+        String str = randomNum8(System.nanoTime());
+        return from10To24(str, 6);
+    }
+
+    public static String generateFileUUID() {
+        String str = randomNum12(System.nanoTime());
+        return from10To32(str, 8);
+    }
+
+    public static String genToken(){
+        return from10To32(randomNum12(System.currentTimeMillis()),8) + from10To32(randomNum12(System.nanoTime()),8);
+    }
+
+    public static void main(String[] args) {
+        Set set = new HashSet();
+        String str;
+        for (int i = 0; i < 300; i++) {
+            str = generateShortUUID();
+            System.out.println(str);
+            set.add(str);
+        }
+        System.out.println(set.size());
+    }
+}

+ 10 - 0
liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringAware.java

@@ -4,11 +4,13 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ReflectUtil;
 import com.yomahub.liteflow.spi.ContextAware;
 import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 import org.springframework.beans.factory.support.GenericBeanDefinition;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ConfigurableApplicationContext;
 
 /**
  * 基于代码形式的spring上下文工具类
@@ -64,6 +66,14 @@ public class SpringAware implements ApplicationContextAware, ContextAware {
         return registerBean(c.getName(), c);
     }
 
+    @Override
+    public <T> T registerBean(String beanName, Object bean) {
+        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
+        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getAutowireCapableBeanFactory();
+        defaultListableBeanFactory.registerSingleton(beanName,bean);
+        return (T) configurableApplicationContext.getBean(beanName);
+    }
+
     public <T> T registerOrGet(String beanName, Class<T> clazz) {
         if (ObjectUtil.isNull(applicationContext)){
             return null;

+ 13 - 0
liteflow-spring/src/main/java/com/yomahub/liteflow/spring/ComponentScanner.java

@@ -12,6 +12,7 @@ import com.yomahub.liteflow.aop.ICmpAroundAspect;
 import com.yomahub.liteflow.core.NodeComponent;
 import com.yomahub.liteflow.property.LiteflowConfig;
 import com.yomahub.liteflow.util.LOGOPrinter;
+import com.yomahub.liteflow.util.LiteFlowProxyUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeansException;
@@ -55,17 +56,29 @@ public class ComponentScanner implements BeanPostProcessor {
     @Override
     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
         Class clazz = bean.getClass();
+
+        //判断是不是声明式组件
+        //如果是,就缓存到类属性的map中
+        if (LiteFlowProxyUtil.isMarkedCmp(bean.getClass())){
+            LOG.info("proxy component[{}] has been found", beanName);
+            NodeComponent nodeComponent = LiteFlowProxyUtil.proxy2NodeComponent(bean, beanName);
+            nodeComponentMap.put(beanName, nodeComponent);
+            return nodeComponent;
+        }
+
         // 组件的扫描发现,扫到之后缓存到类属性map中
         if (NodeComponent.class.isAssignableFrom(clazz)) {
             LOG.info("component[{}] has been found", beanName);
             NodeComponent nodeComponent = (NodeComponent) bean;
             nodeComponentMap.put(beanName, nodeComponent);
+            return nodeComponent;
         }
 
         // 组件Aop的实现类加载
         if (ICmpAroundAspect.class.isAssignableFrom(clazz)) {
             LOG.info("component aspect implement[{}] has been found", beanName);
             cmpAroundAspect = (ICmpAroundAspect) bean;
+            return cmpAroundAspect;
         }
 
         return bean;

+ 69 - 0
liteflow-testcase-declare-component/pom.xml

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>liteflow</artifactId>
+        <groupId>com.yomahub</groupId>
+        <version>2.6.14</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>liteflow-testcase-declare-component</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.yomahub</groupId>
+            <artifactId>liteflow-spring-boot-starter</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <version>${springboot.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjweaver</artifactId>
+            <version>1.8.13</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.101tec</groupId>
+            <artifactId>zkclient</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.yomahub</groupId>
+            <artifactId>liteflow-script-qlexpress</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${springboot.version}</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <version>2.8.2</version>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 20 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/BaseTest.java

@@ -0,0 +1,20 @@
+package com.yomahub.liteflow.test;
+
+import com.yomahub.liteflow.flow.FlowBus;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.spi.holder.SpiFactoryCleaner;
+import com.yomahub.liteflow.spring.ComponentScanner;
+import com.yomahub.liteflow.thread.ExecutorHelper;
+import org.junit.AfterClass;
+
+public class BaseTest {
+
+    @AfterClass
+    public static void cleanScanCache(){
+        ComponentScanner.cleanCache();
+        FlowBus.cleanCache();
+        ExecutorHelper.loadInstance().clearExecutorServiceMap();
+        SpiFactoryCleaner.clean();
+        LiteflowConfigGetter.clean();
+    }
+}

+ 42 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/AbsoluteConfigPathSpringbootTest.java

@@ -0,0 +1,42 @@
+package com.yomahub.liteflow.test.absoluteConfigPath;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+/**
+ * springboot环境下异步线程超时日志打印测试
+ * @author Bryan.Zhang
+ * @since 2.6.4
+ */
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/absoluteConfigPath/application.properties")
+@SpringBootTest(classes = AbsoluteConfigPathSpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.absoluteConfigPath.cmp"})
+public class AbsoluteConfigPathSpringbootTest extends BaseTest {
+
+    private final Logger log = LoggerFactory.getLogger(this.getClass());
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Test
+    public void testAbsoluteConfig() throws Exception{
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "arg");
+        Assert.assertTrue(response.isSuccess());
+    }
+}

+ 24 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/ACmp.java

@@ -0,0 +1,24 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.absoluteConfigPath.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("a")
+@LiteflowCmpDefine
+public class ACmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("ACmp executed!");
+	}
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/BCmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.absoluteConfigPath.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("b")
+@LiteflowCmpDefine
+public class BCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("BCmp executed!");
+	}
+
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/absoluteConfigPath/cmp/CCmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.absoluteConfigPath.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("c")
+@LiteflowCmpDefine
+public class CCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("CCmp executed!");
+	}
+
+}

+ 56 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/CustomAOPSpringbootTest.java

@@ -0,0 +1,56 @@
+package com.yomahub.liteflow.test.aop;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import com.yomahub.liteflow.test.aop.aspect.CustomAspect;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+/**
+ * 切面场景单元测试
+ * 在声明式组件场景中,自定义aspect的aop不生效的,因为生成的代理类并不是原类,也不是原类的子类,而是NodeComponent的子类
+ * 所以切不到,暂且没有想出办法来解决,这个测试类暂时不用
+ * @author Bryan.Zhang
+ */
+/*@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/aop/application.properties")
+@SpringBootTest(classes = CustomAOPSpringbootTest.class)
+@EnableAutoConfiguration
+@Import(CustomAspect.class)
+@ComponentScan({"com.yomahub.liteflow.test.aop.cmp1","com.yomahub.liteflow.test.aop.cmp2"})*/
+public class CustomAOPSpringbootTest extends BaseTest {
+
+    /*@Resource
+    private FlowExecutor flowExecutor;
+
+    //测试自定义AOP,串行场景
+    @Test
+    public void testCustomAopS() {
+        LiteflowResponse<DefaultSlot> response= flowExecutor.execute2Resp("chain1", "it's a request");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("before_after", response.getSlot().getData("a"));
+        Assert.assertEquals("before_after", response.getSlot().getData("b"));
+        Assert.assertEquals("before_after", response.getSlot().getData("c"));
+    }
+
+    //测试自定义AOP,并行场景
+    @Test
+    public void testCustomAopP() {
+        LiteflowResponse<DefaultSlot> response= flowExecutor.execute2Resp("chain2", "it's a request");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("before_after", response.getSlot().getData("a"));
+        Assert.assertEquals("before_after", response.getSlot().getData("b"));
+        Assert.assertEquals("before_after", response.getSlot().getData("c"));
+    }*/
+}

+ 76 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/GlobalAOPSpringbootTest.java

@@ -0,0 +1,76 @@
+package com.yomahub.liteflow.test.aop;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.spring.ComponentScanner;
+import com.yomahub.liteflow.test.BaseTest;
+import com.yomahub.liteflow.test.aop.aspect.CmpAspect;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+/**
+ * 切面场景单元测试
+ * @author Bryan.Zhang
+ */
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/aop/application.properties")
+@SpringBootTest(classes = GlobalAOPSpringbootTest.class)
+@EnableAutoConfiguration
+@Import(CmpAspect.class)
+@ComponentScan({"com.yomahub.liteflow.test.aop.cmp1","com.yomahub.liteflow.test.aop.cmp2"})
+public class GlobalAOPSpringbootTest extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    //测试全局AOP,串行场景
+    @Test
+    public void testGlobalAopS() {
+        LiteflowResponse<DefaultSlot> response= flowExecutor.execute2Resp("chain1", "it's a request");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("before_after", response.getSlot().getData("a"));
+        Assert.assertEquals("before_after", response.getSlot().getData("b"));
+        Assert.assertEquals("before_after", response.getSlot().getData("c"));
+        Assert.assertEquals("before_after", response.getSlot().getData("d"));
+        Assert.assertEquals("before_after", response.getSlot().getData("e"));
+    }
+
+    //测试全局AOP,并行场景
+    @Test
+    public void testGlobalAopP() {
+        LiteflowResponse<DefaultSlot> response= flowExecutor.execute2Resp("chain2", "it's a request");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("before_after", response.getSlot().getData("a"));
+        Assert.assertEquals("before_after", response.getSlot().getData("b"));
+        Assert.assertEquals("before_after", response.getSlot().getData("c"));
+        Assert.assertEquals("before_after", response.getSlot().getData("d"));
+        Assert.assertEquals("before_after", response.getSlot().getData("e"));
+    }
+
+    @Test
+    public void testGlobalAopException() {
+        LiteflowResponse<DefaultSlot> response= flowExecutor.execute2Resp("chain3", "it's a request");
+        Assert.assertFalse(response.isSuccess());
+        Assert.assertEquals("before_after", response.getSlot().getData("a"));
+        Assert.assertEquals("before_after", response.getSlot().getData("b"));
+        Assert.assertEquals("before_after", response.getSlot().getData("c"));
+        Assert.assertEquals("before_after", response.getSlot().getData("f"));
+    }
+
+    @AfterClass
+    public static void cleanScanCache(){
+        BaseTest.cleanScanCache();
+        ComponentScanner.cmpAroundAspect = null;
+    }
+}

+ 17 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/aspect/CmpAspect.java

@@ -0,0 +1,17 @@
+package com.yomahub.liteflow.test.aop.aspect;
+
+import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.aop.ICmpAroundAspect;
+import com.yomahub.liteflow.entity.data.Slot;
+
+public class CmpAspect implements ICmpAroundAspect {
+    @Override
+    public void beforeProcess(String nodeId, Slot slot) {
+        slot.setData(nodeId, "before");
+    }
+
+    @Override
+    public void afterProcess(String nodeId, Slot slot) {
+        slot.setData(nodeId, StrUtil.format("{}_{}", slot.getData(nodeId), "after"));
+    }
+}

+ 27 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/aspect/CustomAspect.java

@@ -0,0 +1,27 @@
+package com.yomahub.liteflow.test.aop.aspect;
+
+import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.entity.data.Slot;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+
+@Aspect
+public class CustomAspect {
+
+    @Pointcut("execution(* com.yomahub.liteflow.test.aop.cmp1.*.process(*))")
+    public void cut() {
+    }
+
+    @Around("cut()")
+    public Object around(ProceedingJoinPoint jp) throws Throwable {
+        NodeComponent cmp = (NodeComponent) jp.getThis();
+        Slot slot = cmp.getSlot();
+        slot.setData(cmp.getNodeId(), "before");
+        Object returnObj = jp.proceed();
+        slot.setData(cmp.getNodeId(), StrUtil.format("{}_{}", slot.getData(cmp.getNodeId()), "after"));
+        return returnObj;
+    }
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp1/ACmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.aop.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("a")
+@LiteflowCmpDefine
+public class ACmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("Acomp executed!");
+	}
+
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp1/BCmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.aop.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("b")
+@LiteflowCmpDefine
+public class BCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("Bcomp executed!");
+	}
+
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp1/CCmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.aop.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("c")
+@LiteflowCmpDefine
+public class CCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("Ccomp executed!");
+	}
+
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp2/DCmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.aop.cmp2;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("d")
+@LiteflowCmpDefine
+public class DCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("Dcomp executed!");
+	}
+
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp2/ECmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.aop.cmp2;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("e")
+@LiteflowCmpDefine
+public class ECmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("Ecomp executed!");
+	}
+
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/aop/cmp2/FCmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.aop.cmp2;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("f")
+@LiteflowCmpDefine
+public class FCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		throw new RuntimeException("test error");
+	}
+
+}

+ 134 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/AsyncNodeSpringbootTest.java

@@ -0,0 +1,134 @@
+package com.yomahub.liteflow.test.asyncNode;
+
+import cn.hutool.core.collection.ListUtil;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import com.yomahub.liteflow.test.asyncNode.exception.TestException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+/**
+ * 测试隐式调用子流程
+ * 单元测试
+ *
+ * @author ssss
+ */
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/asyncNode/application.properties")
+@SpringBootTest(classes = AsyncNodeSpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.asyncNode.cmp"})
+public class AsyncNodeSpringbootTest extends BaseTest {
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    /*****
+     * 标准chain 嵌套选择 嵌套子chain进行执行
+     * 验证了when情况下 多个node是并行执行
+     * 验证了默认参数情况下 when可以加载执行
+     * **/
+    @Test
+    public void testAsyncFlow1() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "it's a base request");
+        Assert.assertTrue(response.isSuccess());
+        System.out.println(response.getSlot().getExecuteStepStr());
+    }
+
+    //这个和test1有点类似,只不过进一步验证了步骤
+    @Test
+    public void testAsyncFlow2() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain2", "it's a base request");
+        Assert.assertTrue(ListUtil.toList("b==>j==>g==>f==>h","b==>j==>g==>h==>f",
+                "b==>j==>h==>g==>f","b==>j==>h==>f==>g",
+                "b==>j==>f==>h==>g","b==>j==>f==>g==>h"
+                ).contains(response.getSlot().getExecuteStepStr()));
+    }
+
+    //测试errorResume,默认的errorResume为false,这里测试默认的
+    @Test
+    public void testAsyncFlow3_1() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain3-1", "it's a base request");
+        Assert.assertFalse(response.isSuccess());
+        Assert.assertEquals(response.getSlot().getException().getClass(), TestException.class);
+    }
+
+    //测试errorResume,默认的errorResume为false,这里设置为true
+    @Test
+    public void testAsyncFlow3_2() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain3-2", "it's a base request");
+        Assert.assertTrue(response.isSuccess());
+    }
+
+    //相同group的并行组,会合并,并且errorResume根据第一个when来,这里第一个when配置了不抛错
+    @Test
+    public void testAsyncFlow4() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain4", "it's a base request");
+        //因为不记录错误,所以最终结果是true
+        Assert.assertTrue(response.isSuccess());
+        //因为是并行组,所以即便抛错了,其他组件也会执行,i在流程里配置了2遍,i抛错,但是也执行了2遍,这里验证下
+        Integer count = response.getSlot().getData("count");
+        Assert.assertEquals(new Integer(2), count);
+        //因为配置了不抛错,所以response里的cause应该为null
+        Assert.assertNull(response.getCause());
+    }
+
+    //相同group的并行组,会合并,并且errorResume根据第一个when来,这里第一个when配置了会抛错
+    @Test
+    public void testAsyncFlow5() throws Exception {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain5", "it's a base request");
+        //整个并行组是报错的,所以最终结果是false
+        Assert.assertFalse(response.isSuccess());
+        //因为是并行组,所以即便抛错了,其他组件也会执行,i在流程里配置了2遍,i抛错,但是也执行了2遍,这里验证下
+        Integer count = response.getSlot().getData("count");
+        Assert.assertEquals(new Integer(2), count);
+        //因为第一个when配置了会报错,所以response里的cause里应该会有TestException
+        Assert.assertEquals(TestException.class, response.getCause().getClass());
+    }
+
+    //不同group的并行组,不会合并,第一个when的errorResume是false,会抛错,那第二个when就不会执行
+    @Test
+    public void testAsyncFlow6() throws Exception {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain6", "it's a base request");
+        //第一个when会抛错,所以最终结果是false
+        Assert.assertFalse(response.isSuccess());
+        //因为是不同组并行组,第一组的when里的i就抛错了,所以i就执行了1遍
+        Integer count = response.getSlot().getData("count");
+        Assert.assertEquals(new Integer(1), count);
+        //第一个when会报错,所以最终response的cause里应该会有TestException
+        Assert.assertEquals(TestException.class, response.getCause().getClass());
+    }
+
+    //不同group的并行组,不会合并,第一个when的errorResume是true,不会报错,那第二个when还会继续执行,但是第二个when的errorResume是false,所以第二个when会报错
+    @Test
+    public void testAsyncFlow7() throws Exception {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain7", "it's a base request");
+        //第二个when会抛错,所以最终结果是false
+        Assert.assertFalse(response.isSuccess());
+        //  传递了slotIndex,则set的size==2
+        Integer count = response.getSlot().getData("count");
+        Assert.assertEquals(new Integer(2), count);
+        //第一个when会报错,所以最终response的cause里应该会有TestException
+        Assert.assertEquals(TestException.class, response.getCause().getClass());
+    }
+
+    //测试任意异步一个执行完即继续的场景
+    //d g h并行,配置了any=true,其中d耗时1秒,g耗时0.5秒,其他都不设耗时
+    //最终执行效果应该是h先返回,然后执行abc,最后gd
+    //这里要注意的是,由于step是先加入,所以step的打印顺序并不是这样的。但是实际执行是正确的
+    @Test
+    public void testAsyncFlow8() throws Exception {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain8", "it's a base request");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertTrue(response.getSlot().getData("check").toString().startsWith("habc"));
+    }
+}

+ 28 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ACmp.java

@@ -0,0 +1,28 @@
+package com.yomahub.liteflow.test.asyncNode.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.entity.data.Slot;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+
+@Component("a")
+@LiteflowCmpDefine
+public class ACmp{
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) {
+        Slot slot = bindCmp.getSlot();
+        synchronized (NodeComponent.class){
+            if (slot.hasData("check")){
+                String str = slot.getData("check");
+                str += bindCmp.getNodeId();
+                slot.setData("check", str);
+            }else{
+                slot.setData("check", bindCmp.getNodeId());
+            }
+        }
+        System.out.println("Acomp executed!");
+    }
+}

+ 28 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/BCmp.java

@@ -0,0 +1,28 @@
+package com.yomahub.liteflow.test.asyncNode.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.entity.data.Slot;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+
+@Component("b")
+@LiteflowCmpDefine
+public class BCmp{
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) {
+        Slot slot = bindCmp.getSlot();
+        synchronized (NodeComponent.class){
+            if (slot.hasData("check")){
+                String str = slot.getData("check");
+                str += bindCmp.getNodeId();
+                slot.setData("check", str);
+            }else{
+                slot.setData("check", bindCmp.getNodeId());
+            }
+        }
+        System.out.println("Bcomp executed!");
+    }
+}

+ 28 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/CCmp.java

@@ -0,0 +1,28 @@
+package com.yomahub.liteflow.test.asyncNode.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.entity.data.Slot;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+
+@Component("c")
+@LiteflowCmpDefine
+public class CCmp{
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) throws Exception {
+        Slot slot = bindCmp.getSlot();
+        synchronized (NodeComponent.class){
+            if (slot.hasData("check")){
+                String str = slot.getData("check");
+                str += bindCmp.getNodeId();
+                slot.setData("check", str);
+            }else{
+                slot.setData("check", bindCmp.getNodeId());
+            }
+        }
+        System.out.println("Ccomp executed!");
+    }
+}

+ 29 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/DCmp.java

@@ -0,0 +1,29 @@
+package com.yomahub.liteflow.test.asyncNode.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.entity.data.Slot;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+
+@Component("d")
+@LiteflowCmpDefine
+public class DCmp{
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) throws Exception {
+        Thread.sleep(1000);
+        Slot slot = bindCmp.getSlot();
+        synchronized (NodeComponent.class){
+            if (slot.hasData("check")){
+                String str = slot.getData("check");
+                str += bindCmp.getNodeId();
+                slot.setData("check", str);
+            }else{
+                slot.setData("check", bindCmp.getNodeId());
+            }
+        }
+        System.out.println("Dcomp executed!");
+    }
+}

+ 20 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ECmp.java

@@ -0,0 +1,20 @@
+package com.yomahub.liteflow.test.asyncNode.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCondCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.core.NodeCondComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+
+@Component("e")
+@LiteflowCondCmpDefine
+public class ECmp{
+
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS_COND)
+    public String processCond(NodeComponent bindCmp) throws Exception {
+        System.out.println("Ecomp executed!");
+        return "g";
+    }
+}

+ 18 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/FCmp.java

@@ -0,0 +1,18 @@
+package com.yomahub.liteflow.test.asyncNode.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+
+@Component("f")
+@LiteflowCmpDefine
+public class FCmp{
+
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) throws Exception {
+        System.out.println("Fcomp executed!");
+    }
+}

+ 30 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/GCmp.java

@@ -0,0 +1,30 @@
+package com.yomahub.liteflow.test.asyncNode.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.entity.data.Slot;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+
+@Component("g")
+@LiteflowCmpDefine
+public class GCmp{
+
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) throws Exception {
+        Thread.sleep(500);
+        Slot slot = bindCmp.getSlot();
+        synchronized (NodeComponent.class){
+            if (slot.hasData("check")){
+                String str = slot.getData("check");
+                str += bindCmp.getNodeId();
+                slot.setData("check", str);
+            }else{
+                slot.setData("check", bindCmp.getNodeId());
+            }
+        }
+        System.out.println("Gcomp executed!");
+    }
+}

+ 30 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/HCmp.java

@@ -0,0 +1,30 @@
+package com.yomahub.liteflow.test.asyncNode.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.entity.data.Slot;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+
+@Component("h")
+@LiteflowCmpDefine
+public class HCmp{
+
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) throws Exception {
+        Slot slot = bindCmp.getSlot();
+        synchronized (NodeComponent.class){
+            if (slot.hasData("check")){
+                String str = slot.getData("check");
+                str += bindCmp.getNodeId();
+                slot.setData("check", str);
+            }else{
+                slot.setData("check", bindCmp.getNodeId());
+            }
+        }
+
+        System.out.println("Hcomp executed!");
+    }
+}

+ 28 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/ICmp.java

@@ -0,0 +1,28 @@
+package com.yomahub.liteflow.test.asyncNode.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.entity.data.Slot;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import com.yomahub.liteflow.test.asyncNode.exception.TestException;
+import org.springframework.stereotype.Component;
+
+
+@Component("i")
+@LiteflowCmpDefine
+public class ICmp {
+
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) throws Exception {
+        Slot slot = bindCmp.getSlot();
+        if (slot.hasData("count")){
+            Integer count = slot.getData("count");
+            slot.setData("count", ++count);
+        } else{
+            slot.setData("count", 1);
+        }
+        System.out.println("Icomp executed! throw Exception!");
+        throw new TestException();
+    }
+}

+ 21 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/cmp/JCmp.java

@@ -0,0 +1,21 @@
+package com.yomahub.liteflow.test.asyncNode.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowCondCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.core.NodeCondComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+
+@Component("j")
+@LiteflowCondCmpDefine
+public class JCmp{
+
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS_COND)
+    public String processCond(NodeComponent bindCmp) throws Exception {
+        System.out.println("Jcomp executed!");
+        return "chain3";
+    }
+}

+ 4 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/asyncNode/exception/TestException.java

@@ -0,0 +1,4 @@
+package com.yomahub.liteflow.test.asyncNode.exception;
+
+public class TestException extends Exception{
+}

+ 39 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/BaseSpringbootTest.java

@@ -0,0 +1,39 @@
+package com.yomahub.liteflow.test.base;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+/**
+ * springboot环境最普通的例子测试
+ * @author Bryan.Zhang
+ * @since 2.6.4
+ */
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/base/application.properties")
+@SpringBootTest(classes = BaseSpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.base.cmp"})
+public class BaseSpringbootTest extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Test
+    public void testBase() throws Exception{
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "arg");
+        Assert.assertTrue(response.isSuccess());
+    }
+
+}

+ 24 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/cmp/ACmp.java

@@ -0,0 +1,24 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.base.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("a")
+@LiteflowCmpDefine
+public class ACmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("ACmp executed!");
+	}
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/cmp/BCmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.base.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("b")
+@LiteflowCmpDefine
+public class BCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("BCmp executed!");
+	}
+
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/cmp/CCmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.base.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("c")
+@LiteflowCmpDefine
+public class CCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("CCmp executed!");
+	}
+
+}

+ 31 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/cmp/DCmp.java

@@ -0,0 +1,31 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.base.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+@Component("d")
+@LiteflowCmpDefine
+public class DCmp{
+
+	@Resource
+	private TestDomain testDomain;
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		testDomain.sayHi();
+		System.out.println("CCmp executed!");
+	}
+
+}

+ 10 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/base/cmp/TestDomain.java

@@ -0,0 +1,10 @@
+package com.yomahub.liteflow.test.base.cmp;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class TestDomain {
+    public void sayHi(){
+        System.out.println("hello");
+    }
+}

+ 217 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/BuilderSpringbootTest1.java

@@ -0,0 +1,217 @@
+package com.yomahub.liteflow.test.builder;
+
+import com.yomahub.liteflow.builder.LiteFlowChainBuilder;
+import com.yomahub.liteflow.builder.LiteFlowConditionBuilder;
+import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.ExecutableEntity;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.enums.NodeTypeEnum;
+import com.yomahub.liteflow.test.BaseTest;
+import com.yomahub.liteflow.test.builder.cmp1.*;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+//基于builder模式的单元测试
+//这里只是最基本的builder模式的测试,只是为了验证在springboot模式下的正常性
+//更详细的builder模式测试用例会单独拉testcase去做
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = BuilderSpringbootTest1.class)
+@EnableAutoConfiguration
+public class BuilderSpringbootTest1 extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    //基于普通组件的builder模式测试
+    @Test
+    public void testBuilder() throws Exception {
+        LiteFlowNodeBuilder.createNode().setId("a")
+                .setName("组件A")
+                .setType(NodeTypeEnum.COMMON)
+                .setClazz("com.yomahub.liteflow.test.builder.cmp1.ACmp")
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("b")
+                .setName("组件B")
+                .setType(NodeTypeEnum.COMMON)
+                .setClazz("com.yomahub.liteflow.test.builder.cmp1.BCmp")
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("c")
+                .setName("组件C")
+                .setType(NodeTypeEnum.COMMON)
+                .setClazz("com.yomahub.liteflow.test.builder.cmp1.CCmp")
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("d")
+                .setName("组件D")
+                .setType(NodeTypeEnum.COMMON)
+                .setClazz("com.yomahub.liteflow.test.builder.cmp1.DCmp")
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("e")
+                .setName("组件E")
+                .setType(NodeTypeEnum.COMMON)
+                .setClazz("com.yomahub.liteflow.test.builder.cmp1.ECmp")
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("f")
+                .setName("组件F")
+                .setType(NodeTypeEnum.COMMON)
+                .setClazz("com.yomahub.liteflow.test.builder.cmp1.FCmp")
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("g")
+                .setName("组件G")
+                .setType(NodeTypeEnum.COMMON)
+                .setClazz("com.yomahub.liteflow.test.builder.cmp1.GCmp")
+                .build();
+
+
+        LiteFlowChainBuilder.createChain().setChainName("chain2").setCondition(
+                LiteFlowConditionBuilder.createThenCondition().setValue("c,d").build()
+        ).build();
+
+        LiteFlowChainBuilder.createChain().setChainName("chain1").setCondition(
+                LiteFlowConditionBuilder
+                        .createThenCondition()
+                        .setValue("a,b").build()
+        ).setCondition(
+                LiteFlowConditionBuilder.createWhenCondition()
+                        .setValue("e(f|g|chain2)").build()
+        ).build();
+
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getSlot().getExecuteStepStr());
+    }
+
+    //基于普通组件的builder模式测试
+    @Test
+    public void testBuilderForClassAndCode() throws Exception {
+        LiteFlowNodeBuilder.createNode().setId("a")
+                .setName("组件A")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(ACmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("b")
+                .setName("组件B")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(BCmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("c")
+                .setName("组件C")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(CCmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("d")
+                .setName("组件D")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(DCmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("e")
+                .setName("组件E")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(ECmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("f")
+                .setName("组件F")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(FCmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("g")
+                .setName("组件G")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(GCmp.class)
+                .build();
+
+
+        LiteFlowChainBuilder.createChain().setChainName("chain2").setCondition(
+                LiteFlowConditionBuilder.createThenCondition().setValue("c,d").build()
+        ).build();
+
+        LiteFlowChainBuilder.createChain().setChainName("chain1").setCondition(
+                LiteFlowConditionBuilder
+                        .createThenCondition()
+                        .setValue("a,b").build()
+        ).setCondition(
+                LiteFlowConditionBuilder.createWhenCondition()
+                        .setValue("e(f|g|chain2)").build()
+        ).build();
+
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getSlot().getExecuteStepStr());
+    }
+
+
+    //基于普通组件的builder模式测试
+    @Test
+    public void testBuilderForConditionNode() throws Exception {
+        LiteFlowNodeBuilder.createNode().setId("a")
+                .setName("组件A")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(ACmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("b")
+                .setName("组件B")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(BCmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("c")
+                .setName("组件C")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(CCmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("d")
+                .setName("组件D")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(DCmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("e")
+                .setName("组件E")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(ECmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("f")
+                .setName("组件F")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(FCmp.class)
+                .build();
+        LiteFlowNodeBuilder.createNode().setId("g")
+                .setName("组件G")
+                .setTypeCode(NodeTypeEnum.COMMON.getCode())
+                .setClazz(GCmp.class)
+                .build();
+
+
+        LiteFlowChainBuilder.createChain().setChainName("chain2").setCondition(
+                LiteFlowConditionBuilder.createThenCondition()
+                        .setExecutable(new ExecutableEntity().setId("c"))
+                        .setExecutable(new ExecutableEntity().setId("d"))
+                        .build()
+        ).build();
+
+        LiteFlowChainBuilder.createChain().setChainName("chain1").setCondition(
+                LiteFlowConditionBuilder
+                        .createThenCondition()
+                        .setExecutable(new ExecutableEntity().setId("a").setTag("hello"))
+                        .setExecutable(new ExecutableEntity().setId("b"))
+                        .build()
+        ).setCondition(
+                LiteFlowConditionBuilder.createWhenCondition()
+                        .setExecutable(
+                                new ExecutableEntity().setId("e")
+                                        .addNodeCondComponent(new ExecutableEntity().setId("f").setTag("FHello"))
+                                        .addNodeCondComponent(new ExecutableEntity().setId("g"))
+                                        .addNodeCondComponent(new ExecutableEntity().setId("chain2")
+                                        )).build()
+        ).build();
+
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getSlot().getExecuteStepStr());
+    }
+}

+ 41 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/BuilderSpringbootTest2.java

@@ -0,0 +1,41 @@
+package com.yomahub.liteflow.test.builder;
+
+import com.yomahub.liteflow.builder.LiteFlowChainBuilder;
+import com.yomahub.liteflow.builder.LiteFlowConditionBuilder;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+//基于builder模式的单元测试
+//这里测试的是通过spring去扫描,但是通过代码去构建chain的用例
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = BuilderSpringbootTest2.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.builder.cmp2"})
+public class BuilderSpringbootTest2 extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    //通过spring去扫描组件,通过代码去构建chain
+    @Test
+    public void testBuilder() throws Exception {
+        LiteFlowChainBuilder.createChain().setChainName("chain1").setCondition(
+                LiteFlowConditionBuilder.createThenCondition().setValue("h,i,j").build()
+        ).build();
+
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("h==>i==>j", response.getSlot().getExecuteStepStr());
+    }
+}

+ 22 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ACmp.java

@@ -0,0 +1,22 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.builder.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowCmpDefine
+public class ACmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("ACmp executed!");
+	}
+}

+ 23 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/BCmp.java

@@ -0,0 +1,23 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.builder.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowCmpDefine
+public class BCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("BCmp executed!");
+	}
+
+}

+ 23 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/CCmp.java

@@ -0,0 +1,23 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.builder.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowCmpDefine
+public class CCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("CCmp executed!");
+	}
+
+}

+ 23 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/DCmp.java

@@ -0,0 +1,23 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.builder.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowCmpDefine
+public class DCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("DCmp executed!");
+	}
+
+}

+ 24 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/ECmp.java

@@ -0,0 +1,24 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.builder.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCondCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowCondCmpDefine
+public class ECmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS_COND)
+	public String processCond(NodeComponent bindCmp) throws Exception {
+		System.out.println("ECmp executed!");
+		return "chain2";
+	}
+
+}

+ 23 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/FCmp.java

@@ -0,0 +1,23 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.builder.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowCmpDefine
+public class FCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("FCmp executed!");
+	}
+
+}

+ 23 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp1/GCmp.java

@@ -0,0 +1,23 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.builder.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowCmpDefine
+public class GCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("GCmp executed!");
+	}
+
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp2/HCmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.builder.cmp2;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowComponent("h")
+@LiteflowCmpDefine
+public class HCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("HCmp executed!");
+	}
+
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp2/ICmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.builder.cmp2;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowComponent("i")
+@LiteflowCmpDefine
+public class ICmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("ICmp executed!");
+	}
+
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/builder/cmp2/JCmp.java

@@ -0,0 +1,25 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.builder.cmp2;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowComponent("j")
+@LiteflowCmpDefine
+public class JCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("JCmp executed!");
+	}
+
+}

+ 64 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/LiteflowRetrySpringbootTest.java

@@ -0,0 +1,64 @@
+package com.yomahub.liteflow.test.cmpRetry;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+
+/**
+ * 测试springboot下的节点执行器
+ * @author Bryan.Zhang
+ * @since 2.5.10
+ */
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/cmpRetry/application.properties")
+@SpringBootTest(classes = LiteflowRetrySpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.cmpRetry.cmp"})
+public class LiteflowRetrySpringbootTest extends BaseTest {
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    //全局重试配置测试
+    @Test
+    public void testRetry1() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "arg");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("a==>b==>b==>b", response.getSlot().getExecuteStepStr());
+    }
+
+    //单个组件重试配置测试
+    @Test
+    public void testRetry2() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain2", "arg");
+        Assert.assertFalse(response.isSuccess());
+        Assert.assertEquals("c==>c==>c==>c==>c==>c", response.getSlot().getExecuteStepStr());
+    }
+
+    //单个组件指定异常,但抛出的并不是指定异常的场景测试
+    @Test
+    public void testRetry3() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain3", "arg");
+        Assert.assertFalse(response.isSuccess());
+    }
+
+    //单个组件指定异常重试,抛出的是指定异常或者
+    @Test
+    public void testRetry4() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain4", "arg");
+        Assert.assertFalse(response.isSuccess());
+        Assert.assertEquals("e==>e==>e==>e==>e==>e", response.getSlot().getExecuteStepStr());
+    }
+}

+ 24 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ACmp.java

@@ -0,0 +1,24 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.cmpRetry.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowComponent("a")
+@LiteflowCmpDefine
+public class ACmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("ACmp executed!");
+	}
+}

+ 31 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/BCmp.java

@@ -0,0 +1,31 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.cmpRetry.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowComponent("b")
+@LiteflowCmpDefine
+public class BCmp {
+
+	private int flag = 0;
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("BCmp executed!");
+		if (flag < 2){
+			flag++;
+			throw new RuntimeException("demo exception");
+		}
+	}
+
+}

+ 28 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/CCmp.java

@@ -0,0 +1,28 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.cmpRetry.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.annotation.LiteflowRetry;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowComponent("c")
+@LiteflowRetry(5)
+@LiteflowCmpDefine
+public class CCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("CCmp executed!");
+		throw new RuntimeException("demo exception");
+	}
+
+}

+ 28 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/DCmp.java

@@ -0,0 +1,28 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.cmpRetry.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.annotation.LiteflowRetry;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowComponent("d")
+@LiteflowRetry(retry = 5, forExceptions = {NullPointerException.class})
+@LiteflowCmpDefine
+public class DCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("DCmp executed!");
+		throw new RuntimeException("demo exception");
+	}
+
+}

+ 28 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/cmpRetry/cmp/ECmp.java

@@ -0,0 +1,28 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.cmpRetry.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.annotation.LiteflowRetry;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowComponent("e")
+@LiteflowRetry(retry = 5, forExceptions = {NullPointerException.class})
+@LiteflowCmpDefine
+public class ECmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("ECmp executed!");
+		throw new NullPointerException("demo null exception");
+	}
+
+}

+ 94 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/FlowExecutorSpringbootTest.java

@@ -0,0 +1,94 @@
+package com.yomahub.liteflow.test.component;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.util.ReflectionUtils;
+
+import javax.annotation.Resource;
+
+/**
+ * 组件功能点测试
+ * 单元测试
+ *
+ * @author donguo.tao
+ */
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/component/application.properties")
+@SpringBootTest(classes = FlowExecutorSpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.component.cmp1","com.yomahub.liteflow.test.component.cmp2"})
+public class FlowExecutorSpringbootTest extends BaseTest {
+    private static final Logger LOG = LoggerFactory.getLogger(FlowExecutorSpringbootTest.class);
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    //isAccess方法的功能测试
+    @Test
+    public void testIsAccess() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", 101);
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertNotNull(response.getSlot().getResponseData());
+    }
+
+    //组件抛错的功能点测试
+    @Test(expected = ArithmeticException.class)
+    public void testComponentException() throws Exception {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain2", 0);
+        Assert.assertFalse(response.isSuccess());
+        Assert.assertEquals("/ by zero", response.getMessage());
+        ReflectionUtils.rethrowException(response.getCause());
+    }
+
+    //isContinueOnError方法的功能点测试
+    @Test
+    public void testIsContinueOnError() throws Exception {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain3", 0);
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertNull(response.getCause());
+    }
+
+    //isEnd方法的功能点测试
+    @Test
+    public void testIsEnd() throws Exception {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain4", 10);
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("d",response.getSlot().getExecuteStepStr());
+    }
+
+    //setIsEnd方法的功能点测试
+    @Test
+    public void testSetIsEnd1() throws Exception {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain5", 10);
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("e",response.getSlot().getExecuteStepStr());
+    }
+
+    //条件组件的功能点测试
+    @Test
+    public void testNodeCondComponent() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain6", 0);
+        Assert.assertTrue(response.isSuccess());
+    }
+
+    //测试setIsEnd如果为true,continueError也为true,那不应该continue了
+    @Test
+    public void testSetIsEnd2() throws Exception {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain7", 10);
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertEquals("g",response.getSlot().getExecuteStepStr());
+    }
+
+}

+ 30 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/ACmp.java

@@ -0,0 +1,30 @@
+package com.yomahub.liteflow.test.component.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+import java.util.Objects;
+
+
+@Component("a")
+@LiteflowCmpDefine
+public class ACmp{
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) {
+        System.out.println("AComp executed!");
+        bindCmp.getSlot().setResponseData("AComp executed!");
+    }
+
+    @LiteflowMethod(LiteFlowMethodEnum.IS_ACCESS)
+    public boolean isAccess(NodeComponent bindCmp) {
+        Integer requestData = bindCmp.getSlot().getRequestData();
+        if (Objects.nonNull(requestData) && requestData > 100){
+            return true;
+        }
+        System.out.println("AComp isAccess false.");
+        return false;
+    }
+}

+ 33 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/BCmp.java

@@ -0,0 +1,33 @@
+package com.yomahub.liteflow.test.component.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+import java.util.Objects;
+
+
+@Component("b")
+@LiteflowCmpDefine
+public class BCmp{
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) {
+        System.out.println("BComp executed!");
+        Integer requestData = bindCmp.getSlot().getRequestData();
+        Integer divisor = 130;
+        Integer result = divisor / requestData;
+        bindCmp.getSlot().setResponseData(result);
+    }
+
+    @LiteflowMethod(LiteFlowMethodEnum.IS_ACCESS)
+    public boolean isAccess(NodeComponent bindCmp) {
+        Integer requestData = bindCmp.getSlot().getRequestData();
+        if (Objects.nonNull(requestData)){
+            return true;
+        }
+        return false;
+    }
+
+}

+ 33 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/CCmp.java

@@ -0,0 +1,33 @@
+package com.yomahub.liteflow.test.component.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+import java.util.Objects;
+
+
+@Component("c")
+@LiteflowCmpDefine
+public class CCmp{
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) {
+        System.out.println("CComp executed!");
+        Integer requestData = bindCmp.getSlot().getRequestData();
+        Integer divisor = 130;
+        Integer result = divisor / requestData;
+        bindCmp.getSlot().setResponseData(result);
+        System.out.println("responseData="+Integer.parseInt(bindCmp.getSlot().getResponseData()));
+    }
+
+    @LiteflowMethod(LiteFlowMethodEnum.IS_CONTINUE_ON_ERROR)
+    public boolean isContinueOnError(NodeComponent bindCmp) {
+        Integer requestData = bindCmp.getSlot().getRequestData();
+        if (Objects.nonNull(requestData)){
+            return true;
+        }
+        return false;
+    }
+}

+ 30 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/DCmp.java

@@ -0,0 +1,30 @@
+package com.yomahub.liteflow.test.component.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+import java.util.Objects;
+
+
+@Component("d")
+@LiteflowCmpDefine
+public class DCmp{
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) throws Exception {
+        System.out.println("DComp executed!");
+    }
+
+    @LiteflowMethod(LiteFlowMethodEnum.IS_END)
+    public boolean isEnd(NodeComponent bindCmp) {
+        //组件的process执行完之后才会执行isEnd
+        Object requestData = bindCmp.getSlot().getResponseData();
+        if (Objects.isNull(requestData)){
+            System.out.println("DComp flow isEnd, because of responseData is null.");
+            return true;
+        }
+        return false;
+    }
+}

+ 28 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/ECmp.java

@@ -0,0 +1,28 @@
+package com.yomahub.liteflow.test.component.cmp1;
+
+import com.alibaba.fastjson.JSON;
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+import java.util.Objects;
+
+
+@Component("e")
+@LiteflowCmpDefine
+public class ECmp{
+
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+    public void process(NodeComponent bindCmp) throws Exception {
+        System.out.println("EComp executed!");
+        Object responseData = bindCmp.getSlot().getResponseData();
+        if (Objects.isNull(responseData)){
+            System.out.println("EComp responseData flow must be set end .");
+            //执行到某个条件时,手动结束流程。
+            bindCmp.setIsEnd(true);
+        }
+        System.out.println("EComp responseData responseData=" + JSON.toJSONString(responseData));
+    }
+}

+ 30 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/GCmp.java

@@ -0,0 +1,30 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.component.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("g")
+@LiteflowCmpDefine
+public class GCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("GCmp executed!");
+		bindCmp.setIsEnd(true);
+	}
+
+	@LiteflowMethod(LiteFlowMethodEnum.IS_CONTINUE_ON_ERROR)
+	public boolean isContinueOnError(NodeComponent bindCmp) {
+		return true;
+	}
+}

+ 24 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp1/HCmp.java

@@ -0,0 +1,24 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.component.cmp1;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("h")
+@LiteflowCmpDefine
+public class HCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("HCmp executed!");
+	}
+}

+ 27 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/component/cmp2/FCondCmp.java

@@ -0,0 +1,27 @@
+package com.yomahub.liteflow.test.component.cmp2;
+
+import com.yomahub.liteflow.annotation.LiteflowCondCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.core.NodeCondComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+import java.util.Objects;
+
+
+@Component("f")
+@LiteflowCondCmpDefine
+public class FCondCmp{
+    @LiteflowMethod(LiteFlowMethodEnum.PROCESS_COND)
+    public String processCond(NodeComponent bindCmp) {
+        Integer requestData = bindCmp.getSlot().getRequestData();
+        if (Objects.isNull(requestData)){
+            return "d";
+        } else if(requestData == 0){
+            return "c";
+        } else {
+            return "b";
+        }
+    }
+}

+ 45 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/CustomNodesSpringbootTest.java

@@ -0,0 +1,45 @@
+package com.yomahub.liteflow.test.customNodes;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+/**
+ * springboot环境下自定义声明节点的测试
+ * 不通过spring扫描的方式,通过在配置文件里定义nodes的方式
+ * @author Bryan.Zhang
+ * @since 2.6.4
+ */
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/customNodes/application.properties")
+@SpringBootTest(classes = CustomNodesSpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.customNodes.domain"})
+public class CustomNodesSpringbootTest extends BaseTest {
+
+    private final Logger log = LoggerFactory.getLogger(this.getClass());
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Test
+    public void testCustomNodes() throws Exception{
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "arg");
+        Assert.assertTrue(response.isSuccess());
+        response = flowExecutor.execute2Resp("chain2", "arg");
+        Assert.assertTrue(response.isSuccess());
+    }
+}

+ 22 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ACmp.java

@@ -0,0 +1,22 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customNodes.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowCmpDefine
+public class ACmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("ACmp executed!");
+	}
+}

+ 29 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/BCmp.java

@@ -0,0 +1,29 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customNodes.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import com.yomahub.liteflow.test.customNodes.domain.DemoDomain;
+
+import javax.annotation.Resource;
+
+@LiteflowCmpDefine
+public class BCmp{
+
+	@Resource
+	private DemoDomain demoDomain;
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		demoDomain.sayHi();
+		System.out.println("BCmp executed!");
+	}
+}

+ 23 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/CCmp.java

@@ -0,0 +1,23 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customNodes.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowCmpDefine
+public class CCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("CCmp executed!");
+	}
+
+}

+ 23 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/DCmp.java

@@ -0,0 +1,23 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customNodes.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowCmpDefine
+public class DCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("DCmp executed!");
+	}
+
+}

+ 30 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/ECmp.java

@@ -0,0 +1,30 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customNodes.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import com.yomahub.liteflow.test.customNodes.domain.DemoDomain;
+
+import javax.annotation.Resource;
+
+@LiteflowCmpDefine
+public class ECmp{
+
+	@Resource
+	private DemoDomain demoDomain;
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		demoDomain.sayHi();
+		System.out.println("ECmp executed!");
+	}
+
+}

+ 23 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/cmp/FCmp.java

@@ -0,0 +1,23 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customNodes.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+
+@LiteflowCmpDefine
+public class FCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("FCmp executed!");
+	}
+
+}

+ 11 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customNodes/domain/DemoDomain.java

@@ -0,0 +1,11 @@
+package com.yomahub.liteflow.test.customNodes.domain;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class DemoDomain {
+
+    public void sayHi(){
+        System.out.println("hi");
+    }
+}

+ 25 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor1.java

@@ -0,0 +1,25 @@
+package com.yomahub.liteflow.test.customWhenThreadPool;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.thread.ExecutorBuilder;
+
+import java.util.concurrent.ExecutorService;
+
+public class CustomThreadExecutor1 implements ExecutorBuilder {
+
+    @Override
+    public ExecutorService buildExecutor() {
+        LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
+        //只有在非spring的场景下liteflowConfig才会为null
+        if (ObjectUtil.isNull(liteflowConfig)) {
+            liteflowConfig = new LiteflowConfig();
+        }
+        return buildDefaultExecutor(
+                liteflowConfig.getWhenMaxWorkers(),
+                liteflowConfig.getWhenMaxWorkers(),
+                liteflowConfig.getWhenQueueLimit(),
+                "customer-when-1-thead-");
+    }
+}

+ 24 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor2.java

@@ -0,0 +1,24 @@
+package com.yomahub.liteflow.test.customWhenThreadPool;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.thread.ExecutorBuilder;
+
+import java.util.concurrent.ExecutorService;
+
+public class CustomThreadExecutor2 implements ExecutorBuilder {
+    @Override
+    public ExecutorService buildExecutor() {
+        LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
+        //只有在非spring的场景下liteflowConfig才会为null
+        if (ObjectUtil.isNull(liteflowConfig)) {
+            liteflowConfig = new LiteflowConfig();
+        }
+        return buildDefaultExecutor(
+                liteflowConfig.getWhenMaxWorkers(),
+                liteflowConfig.getWhenMaxWorkers(),
+                liteflowConfig.getWhenQueueLimit(),
+                "customer-when-2-thead-");
+    }
+}

+ 24 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomThreadExecutor3.java

@@ -0,0 +1,24 @@
+package com.yomahub.liteflow.test.customWhenThreadPool;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.thread.ExecutorBuilder;
+
+import java.util.concurrent.ExecutorService;
+
+public class CustomThreadExecutor3 implements ExecutorBuilder {
+    @Override
+    public ExecutorService buildExecutor() {
+        LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
+        //只有在非spring的场景下liteflowConfig才会为null
+        if (ObjectUtil.isNull(liteflowConfig)) {
+            liteflowConfig = new LiteflowConfig();
+        }
+        return buildDefaultExecutor(
+                liteflowConfig.getWhenMaxWorkers(),
+                liteflowConfig.getWhenMaxWorkers(),
+                liteflowConfig.getWhenQueueLimit(),
+                "customer-when-3-thead-");
+    }
+}

+ 72 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/CustomWhenThreadPoolSpringbootTest.java

@@ -0,0 +1,72 @@
+package com.yomahub.liteflow.test.customWhenThreadPool;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+/**
+ * springboot环境下异步线程超时日志打印测试
+ *
+ * @author Bryan.Zhang
+ * @since 2.6.4
+ */
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/customWhenThreadPool/application.properties")
+@SpringBootTest(classes = CustomWhenThreadPoolSpringbootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.customWhenThreadPool.cmp"})
+public class CustomWhenThreadPoolSpringbootTest extends BaseTest {
+
+    private final Logger log = LoggerFactory.getLogger(this.getClass());
+
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    /**
+     * 测试全局线程池配置
+     */
+    @Test
+    public void testGlobalThreadPool() {
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain", "arg");
+        Assert.assertTrue(response.isSuccess());
+        Assert.assertTrue(response.getSlot().getData("threadName").toString().startsWith("lf-when-thead"));
+    }
+
+    /**
+     * 测试全局和when上自定义线程池-优先以when上为准
+     */
+    @Test
+    public void testGlobalAndCustomWhenThreadPool() {
+        LiteflowResponse<DefaultSlot> response1 = flowExecutor.execute2Resp("chain1", "arg");
+        Assert.assertTrue(response1.isSuccess());
+        Assert.assertTrue(response1.getSlot().getData("threadName").toString().startsWith("customer-when-1-thead"));
+    }
+
+
+    /**
+     * when配置的线程池可以共用
+     */
+    @Test
+    public void testCustomWhenThreadPool() {
+        // 使用when - thread1
+        testGlobalAndCustomWhenThreadPool();
+        // chain配置同一个thead1
+        LiteflowResponse<DefaultSlot> response2 = flowExecutor.execute2Resp("chain2", "arg");
+        Assert.assertTrue(response2.isSuccess());
+        Assert.assertTrue(response2.getSlot().getData("threadName").toString().startsWith("customer-when-1-thead"));
+
+    }
+}

+ 24 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ACmp.java

@@ -0,0 +1,24 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("a")
+@LiteflowCmpDefine
+public class ACmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		System.out.println("ACmp executed!");
+	}
+}

+ 26 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/BCmp.java

@@ -0,0 +1,26 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("b")
+@LiteflowCmpDefine
+public class BCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		bindCmp.getSlot().setData("threadName", Thread.currentThread().getName());
+		System.out.println("BCmp executed!");
+	}
+
+}

+ 26 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/CCmp.java

@@ -0,0 +1,26 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("c")
+@LiteflowCmpDefine
+public class CCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		bindCmp.getSlot().setData("threadName", Thread.currentThread().getName());
+		System.out.println("CCmp executed!");
+	}
+
+}

+ 26 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/DCmp.java

@@ -0,0 +1,26 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("d")
+@LiteflowCmpDefine
+public class DCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		bindCmp.getSlot().setData("threadName", Thread.currentThread().getName());
+		System.out.println("DCmp executed!");
+	}
+
+}

+ 26 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/ECmp.java

@@ -0,0 +1,26 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("e")
+@LiteflowCmpDefine
+public class ECmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		bindCmp.getSlot().setData("threadName", Thread.currentThread().getName());
+		System.out.println("ECmp executed!");
+	}
+
+}

+ 26 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/customWhenThreadPool/cmp/FCmp.java

@@ -0,0 +1,26 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.springframework.stereotype.Component;
+
+@Component("f")
+@LiteflowCmpDefine
+public class FCmp{
+
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		bindCmp.getSlot().setData("threadName", Thread.currentThread().getName());
+		System.out.println("FCmp executed!");
+	}
+
+}

+ 83 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/exception/ExceptionSpringBootTest.java

@@ -0,0 +1,83 @@
+package com.yomahub.liteflow.test.exception;
+
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.entity.data.DefaultSlot;
+import com.yomahub.liteflow.entity.data.LiteflowResponse;
+import com.yomahub.liteflow.exception.ChainNotFoundException;
+import com.yomahub.liteflow.exception.ConfigErrorException;
+import com.yomahub.liteflow.exception.FlowExecutorNotInitException;
+import com.yomahub.liteflow.exception.FlowSystemException;
+import com.yomahub.liteflow.property.LiteflowConfig;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.util.ReflectionUtils;
+
+import javax.annotation.Resource;
+
+/**
+ * 流程执行异常
+ * 单元测试
+ *
+ * @author zendwang
+ */
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/exception/application.properties")
+@SpringBootTest(classes = ExceptionSpringBootTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.exception.cmp"})
+public class ExceptionSpringBootTest extends BaseTest {
+    
+    @Resource
+    private FlowExecutor flowExecutor;
+
+    @Autowired
+    private ApplicationContext context;
+
+    @Test(expected = ConfigErrorException.class)
+    public void testConfigErrorException() {
+        flowExecutor.setLiteflowConfig(null);
+        flowExecutor.init();
+    }
+
+    @Test(expected = FlowExecutorNotInitException.class)
+    public void testFlowExecutorNotInitException() {
+        LiteflowConfig config = context.getBean(LiteflowConfig.class);
+        config.setRuleSource("error/flow.txt");
+        flowExecutor.init();
+    }
+
+    @Test(expected = ChainNotFoundException.class)
+    public void testChainNotFoundException() throws Exception {
+        flowExecutor.execute("chain0", "it's a request");
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testComponentCustomException() throws Exception {
+        flowExecutor.execute("chain1", "exception");
+    }
+
+    @Test(expected = FlowSystemException.class)
+    public void testNoConditionInChainException() throws Exception {
+        LiteflowResponse response = flowExecutor.execute2Resp("chain2", "test");
+        Assert.assertFalse(response.isSuccess());
+        Assert.assertEquals("no conditionList in this chain[chain2]", response.getMessage());
+        ReflectionUtils.rethrowException(response.getCause());
+    }
+
+    @Test
+    public void testGetSlotFromResponseWhenException() throws Exception{
+        LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain4", "test");
+        Assert.assertFalse(response.isSuccess());
+        Assert.assertNotNull(response.getCause());
+        Assert.assertNotNull(response.getSlot());
+    }
+}

+ 34 - 0
liteflow-testcase-declare-component/src/test/java/com/yomahub/liteflow/test/exception/cmp/ACmp.java

@@ -0,0 +1,34 @@
+/**
+ * <p>Title: liteflow</p>
+ * <p>Description: 轻量级的组件式流程框架</p>
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.exception.cmp;
+
+import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
+import com.yomahub.liteflow.annotation.LiteflowMethod;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component("a")
+@LiteflowCmpDefine
+public class ACmp{
+	
+	private static final Logger LOG = LoggerFactory.getLogger(ACmp.class);
+	
+	@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
+	public void process(NodeComponent bindCmp) {
+		String str = bindCmp.getSlot().getRequestData();
+		if(StrUtil.isNotBlank(str) && str.equals("exception")) {
+			throw new RuntimeException("chain execute execption");
+		}
+		LOG.info("Acomp executed!");
+	}
+
+}

部分文件因为文件数量过多而无法显示