feature #I54VBS 从设计上改善NodeComponent,使之变成声明式的组件
This commit is contained in:
parent
3e6547b1e8
commit
935506a388
|
@ -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>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package com.yomahub.liteflow.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface LiteflowCmpDefine {
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.yomahub.liteflow.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface LiteflowCondCmpDefine {
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<>();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
//进行初始化
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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("$$"));
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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"));
|
||||
}*/
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package com.yomahub.liteflow.test.asyncNode.exception;
|
||||
|
||||
public class TestException extends Exception{
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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-");
|
||||
}
|
||||
}
|
|
@ -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-");
|
||||
}
|
||||
}
|
|
@ -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-");
|
||||
}
|
||||
}
|
|
@ -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"));
|
||||
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue