mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-05-14 20:22:07 +08:00
enhancement #I91AUT 提供在切面出设置 isContinueOnError 参数方法
This commit is contained in:
@@ -12,21 +12,22 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.yomahub.liteflow.core.proxy.LiteFlowProxyUtil;
|
||||
import com.yomahub.liteflow.enums.CmpStepTypeEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
import com.yomahub.liteflow.flow.executor.NodeExecutor;
|
||||
import com.yomahub.liteflow.flow.entity.CmpStep;
|
||||
import com.yomahub.liteflow.flow.executor.DefaultNodeExecutor;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.flow.executor.NodeExecutor;
|
||||
import com.yomahub.liteflow.log.LFLog;
|
||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.spi.holder.CmpAroundAspectHolder;
|
||||
import com.yomahub.liteflow.util.JsonUtil;
|
||||
import com.yomahub.liteflow.flow.entity.CmpStep;
|
||||
import com.yomahub.liteflow.enums.CmpStepTypeEnum;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
import com.yomahub.liteflow.monitor.CompStatistics;
|
||||
import com.yomahub.liteflow.monitor.MonitorBus;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
import com.yomahub.liteflow.spi.holder.CmpAroundAspectHolder;
|
||||
import com.yomahub.liteflow.util.JsonUtil;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
|
||||
@@ -34,6 +35,7 @@ import java.util.Date;
|
||||
* 普通组件抽象类
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @author luo yi
|
||||
*/
|
||||
public abstract class NodeComponent{
|
||||
|
||||
@@ -236,6 +238,10 @@ public abstract class NodeComponent{
|
||||
this.refNodeTL.get().setIsEnd(isEnd);
|
||||
}
|
||||
|
||||
public void setIsContinueOnError(boolean isContinueOnError) {
|
||||
this.refNodeTL.get().setIsContinueOnErrorResult(isContinueOnError);
|
||||
}
|
||||
|
||||
public Integer getSlotIndex() {
|
||||
return this.refNodeTL.get().getSlotIndex();
|
||||
}
|
||||
|
||||
@@ -71,6 +71,9 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
||||
// 是否结束整个流程,这个只对串行流程有效,并行流程无效
|
||||
private TransmittableThreadLocal<Boolean> isEndTL = new TransmittableThreadLocal<>();
|
||||
|
||||
// isContinueOnError 结果
|
||||
private TransmittableThreadLocal<Boolean> isContinueOnErrorResult = new TransmittableThreadLocal<>();
|
||||
|
||||
public Node() {
|
||||
|
||||
}
|
||||
@@ -168,7 +171,7 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
||||
throw new ChainEndException(errorInfo);
|
||||
}
|
||||
// 如果组件覆盖了isContinueOnError方法,返回为true,那即便出了异常,也会继续流程
|
||||
else if (instance.isContinueOnError()) {
|
||||
else if (getIsContinueOnErrorResult() || instance.isContinueOnError()) {
|
||||
String errorMsg = StrUtil.format("component[{}] cause error,but flow is still go on", id);
|
||||
LOG.error(errorMsg);
|
||||
}
|
||||
@@ -185,6 +188,7 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
||||
removeIsEnd();
|
||||
removeLoopIndex();
|
||||
removeAccessResult();
|
||||
removeIsContinueOnErrorResult();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +266,7 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
||||
|
||||
public boolean getAccessResult() {
|
||||
Boolean result = this.accessResult.get();
|
||||
return result == null ? false : result;
|
||||
return result != null && result;
|
||||
}
|
||||
|
||||
public void setAccessResult(boolean accessResult) {
|
||||
@@ -273,6 +277,19 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
||||
this.accessResult.remove();
|
||||
}
|
||||
|
||||
public boolean getIsContinueOnErrorResult() {
|
||||
Boolean result = this.isContinueOnErrorResult.get();
|
||||
return result != null && result;
|
||||
}
|
||||
|
||||
public void setIsContinueOnErrorResult(boolean accessResult) {
|
||||
this.isContinueOnErrorResult.set(accessResult);
|
||||
}
|
||||
|
||||
public void removeIsContinueOnErrorResult() {
|
||||
this.isContinueOnErrorResult.remove();
|
||||
}
|
||||
|
||||
public void setLoopIndex(int index) {
|
||||
this.loopIndexTL.set(index);
|
||||
}
|
||||
@@ -342,6 +359,7 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
||||
node.accessResult = new TransmittableThreadLocal<>();
|
||||
node.slotIndexTL = new TransmittableThreadLocal<>();
|
||||
node.isEndTL = new TransmittableThreadLocal<>();
|
||||
node.isContinueOnErrorResult = new TransmittableThreadLocal<>();
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.yomahub.liteflow.test.aop;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.aop.aspect.CustomOperatorAspect;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 切面场景单元测试
|
||||
*
|
||||
* @author luo yi
|
||||
*/
|
||||
@TestPropertySource(value = "classpath:/aop/application.properties")
|
||||
@SpringBootTest(classes = CustomAOPELOperatorSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@Import(CustomOperatorAspect.class)
|
||||
@ComponentScan({ "com.yomahub.liteflow.test.aop.cmp1", "com.yomahub.liteflow.test.aop.cmp2" })
|
||||
public class CustomAOPELOperatorSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// 设置 isContinueOnError 测试全局 AOP,串行场景
|
||||
@Test
|
||||
public void testGlobalAopErrorWithContinueS() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "it's a request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("before_after", context.getData("a"));
|
||||
Assertions.assertEquals("before_after", context.getData("b"));
|
||||
Assertions.assertEquals("before_after", context.getData("c"));
|
||||
Assertions.assertEquals("before", context.getData("f"));
|
||||
}
|
||||
|
||||
// 设置 isContinueOnError 测试全局 AOP,并行场景
|
||||
@Test
|
||||
public void testGlobalAopErrorWithContinueP() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "it's a request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("before_after", context.getData("a"));
|
||||
Assertions.assertEquals("before_after", context.getData("b"));
|
||||
Assertions.assertEquals("before_after", context.getData("c"));
|
||||
Assertions.assertEquals("before_after", context.getData("e"));
|
||||
Assertions.assertEquals("before", context.getData("f"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.yomahub.liteflow.test.aop;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.spring.ComponentScanner;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.aop.aspect.CmpOperatorAspect;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 切面场景单元测试
|
||||
*
|
||||
* @author luo yi
|
||||
*/
|
||||
@TestPropertySource(value = "classpath:/aop/application.properties")
|
||||
@SpringBootTest(classes = GlobalAOPELOperatorSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@Import(CmpOperatorAspect.class)
|
||||
@ComponentScan({ "com.yomahub.liteflow.test.aop.cmp1", "com.yomahub.liteflow.test.aop.cmp2" })
|
||||
public class GlobalAOPELOperatorSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// 设置 isContinueOnError 测试全局 AOP,串行场景
|
||||
@Test
|
||||
public void testGlobalAopErrorWithContinueS() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "it's a request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("before_after", context.getData("a"));
|
||||
Assertions.assertEquals("before_after", context.getData("b"));
|
||||
Assertions.assertEquals("before_after", context.getData("c"));
|
||||
Assertions.assertEquals("test error", context.getData("f_error"));
|
||||
}
|
||||
|
||||
// 设置 isContinueOnError 测试全局 AOP,并行场景
|
||||
@Test
|
||||
public void testGlobalAopErrorWithContinueP() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "it's a request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("before_after", context.getData("a"));
|
||||
Assertions.assertEquals("before_after", context.getData("b"));
|
||||
Assertions.assertEquals("before_after", context.getData("c"));
|
||||
Assertions.assertEquals("before_after", context.getData("e"));
|
||||
Assertions.assertEquals("test error", context.getData("f_error"));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void cleanScanCache() {
|
||||
BaseTest.cleanScanCache();
|
||||
ComponentScanner.cmpAroundAspect = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.yomahub.liteflow.test.aop.aspect;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.aop.ICmpAroundAspect;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
|
||||
public class CmpOperatorAspect implements ICmpAroundAspect {
|
||||
|
||||
@Override
|
||||
public void beforeProcess(NodeComponent cmp) {
|
||||
DefaultContext context = cmp.getFirstContextBean();
|
||||
context.setData(cmp.getNodeId(), "before");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterProcess(NodeComponent cmp) {
|
||||
DefaultContext context = cmp.getFirstContextBean();
|
||||
context.setData(cmp.getNodeId(), StrUtil.format("{}_{}", context.getData(cmp.getNodeId()), "after"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(NodeComponent cmp) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(NodeComponent cmp, Exception e) {
|
||||
cmp.setIsContinueOnError(true);
|
||||
DefaultContext context = cmp.getFirstContextBean();
|
||||
context.setData(cmp.getNodeId() + "_error", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.yomahub.liteflow.test.aop.aspect;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
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 CustomOperatorAspect {
|
||||
|
||||
@Pointcut("execution(* com.yomahub.liteflow.test.aop.*.*.process())")
|
||||
public void cut() {
|
||||
}
|
||||
|
||||
@Around("cut()")
|
||||
public Object around(ProceedingJoinPoint jp) throws Throwable {
|
||||
NodeComponent cmp = (NodeComponent) jp.getThis();
|
||||
DefaultContext context = cmp.getFirstContextBean();
|
||||
cmp.setIsContinueOnError(true);
|
||||
context.setData(cmp.getNodeId(), "before");
|
||||
Object returnObj = jp.proceed();
|
||||
context.setData(cmp.getNodeId(), StrUtil.format("{}_{}", context.getData(cmp.getNodeId()), "after"));
|
||||
return returnObj;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,4 +11,13 @@
|
||||
<chain name="chain3">
|
||||
THEN(a,b,c,f);
|
||||
</chain>
|
||||
|
||||
<chain name="chain4">
|
||||
THEN(a, f, b, c);
|
||||
</chain>
|
||||
|
||||
<chain name="chain5">
|
||||
THEN(a, b, WHEN(f, e), c);
|
||||
</chain>
|
||||
|
||||
</flow>
|
||||
Reference in New Issue
Block a user