feature #I3N2E2 支持编程时式的注册组件的方式

This commit is contained in:
bryan31 2021-04-20 19:04:22 +08:00
parent d2c7779532
commit 25438c17fe
19 changed files with 237 additions and 23 deletions

View File

@ -0,0 +1,27 @@
package com.yomahub.liteflow.exception;
/**
* 流程规则主要执行器类
* @author Bryan.Zhang
* @since 2.5.3
*/
public class ComponentCannotRegisterException extends RuntimeException {
private static final long serialVersionUID = 1L;
/** 异常信息 */
private String message;
public ComponentCannotRegisterException(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -12,9 +12,15 @@ import java.util.Map;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.entity.flow.Chain;
import com.yomahub.liteflow.entity.flow.Node;
import com.yomahub.liteflow.exception.ComponentCannotRegisterException;
import com.yomahub.liteflow.util.SpringAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 流程元数据类
@ -22,9 +28,11 @@ import com.yomahub.liteflow.util.SpringAware;
*/
public class FlowBus {
private static Map<String, Chain> chainMap = new HashMap<>();
private static final Logger LOG = LoggerFactory.getLogger(FlowBus.class);
private static Map<String, Node> nodeMap = new HashMap<>();
private static final Map<String, Chain> chainMap = new HashMap<>();
private static final Map<String, Node> nodeMap = new HashMap<>();
private FlowBus() {
}
@ -56,6 +64,34 @@ public class FlowBus {
nodeMap.put(nodeId, node);
}
public static void addNode(String nodeId, String cmpClazzStr) throws Exception{
Class<NodeComponent> cmpClazz = (Class<NodeComponent>)Class.forName(cmpClazzStr);
addNode(nodeId, cmpClazz);
}
public static void addNode(String nodeId, Class<? extends NodeComponent> cmpClazz){
try{
Node node = new Node();
node.setId(nodeId);
node.setClazz(cmpClazz.getName());
//以node方式配置本质上是为了适配无spring的环境如果有spring环境其实不用这么配置
//这里的逻辑是判断是否能从spring上下文中取到如果没有spring则就是new instance了
NodeComponent cmpInstance = SpringAware.registerOrGet(cmpClazz);
if (ObjectUtil.isNull(cmpInstance)) {
LOG.warn("couldn't find component class [{}] from spring context", cmpClazz.getName());
cmpInstance = cmpClazz.newInstance();
}
cmpInstance.setNodeId(nodeId);
cmpInstance.setSelf(cmpInstance);
node.setInstance(cmpInstance);
nodeMap.put(nodeId,node);
}catch (Exception e){
String error = StrUtil.format("component[{}] register error", cmpClazz.getName());
LOG.error(error, e);
throw new ComponentCannotRegisterException(error);
}
}
public static Node getNode(String nodeId) {
return nodeMap.get(nodeId);
}

View File

@ -47,28 +47,10 @@ public abstract class XmlFlowParser extends FlowParser{
List<Element> nodeList = rootElement.element("nodes").elements("node");
String id;
String clazz;
Node node;
NodeComponent component;
Class<NodeComponent> nodeComponentClass;
for (Element e : nodeList) {
node = new Node();
id = e.attributeValue("id");
clazz = e.attributeValue("class");
node.setId(id);
node.setClazz(clazz);
nodeComponentClass = (Class<NodeComponent>)Class.forName(clazz);
//以node方式配置本质上是为了适配无spring的环境如果有spring环境其实不用这么配置
//这里的逻辑是判断是否能从spring上下文中取到如果没有spring则就是new instance了
component = SpringAware.registerOrGet(nodeComponentClass);
if (ObjectUtil.isNull(component)) {
LOG.error("couldn't find component class [{}] from spring context", clazz);
component = nodeComponentClass.newInstance();
}
component.setNodeId(id);
component.setSelf(component);
node.setInstance(component);
FlowBus.addNode(id, node);
FlowBus.addNode(id, clazz);
}
} else {
for (Entry<String, NodeComponent> componentEntry : ComponentScanner.nodeComponentMap.entrySet()) {

View File

@ -45,6 +45,10 @@ public class LiteflowConfig {
//异步线程池最大队列数量
private Integer whenQueueLimit;
//是否在启动时解析规则文件
//这个参数主要给编码式注册元数据的场景用的结合FlowBus.addNode一起用
private Boolean parseOnStart;
public String getRuleSource() {
return ruleSource;
}
@ -148,4 +152,16 @@ public class LiteflowConfig {
public void setWhenQueueLimit(Integer whenQueueLimit) {
this.whenQueueLimit = whenQueueLimit;
}
public Boolean isParseOnStart() {
if (ObjectUtil.isNull(parseOnStart)){
return true;
}else{
return parseOnStart;
}
}
public void setParseOnStart(Boolean parseOnStart) {
this.parseOnStart = parseOnStart;
}
}

View File

@ -2,6 +2,7 @@ package com.yomahub.liteflow.springboot;
import com.yomahub.liteflow.core.FlowExecutor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
/**
* 执行器初始化类

View File

@ -7,6 +7,7 @@ import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.util.SpringAware;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -35,6 +36,7 @@ public class LiteflowMainAutoConfiguration {
}
@Bean
@ConditionalOnProperty(prefix = "liteflow",name = "parse-on-start",havingValue = "true")
public LiteflowExecutorInit liteflowExecutorInit(FlowExecutor flowExecutor) {
return new LiteflowExecutorInit(flowExecutor);
}

View File

@ -24,6 +24,10 @@ public class LiteflowProperty {
//异步线程池最大队列数量
private int whenQueueLimit;
//是否在启动时解析规则文件
//这个参数主要给编码式注册元数据的场景用的结合FlowBus.addNode一起用
private boolean parseOnStart;
public String getRuleSource() {
return ruleSource;
}
@ -63,4 +67,12 @@ public class LiteflowProperty {
public void setWhenQueueLimit(int whenQueueLimit) {
this.whenQueueLimit = whenQueueLimit;
}
public boolean isParseOnStart() {
return parseOnStart;
}
public void setParseOnStart(boolean parseOnStart) {
this.parseOnStart = parseOnStart;
}
}

View File

@ -33,6 +33,7 @@ public class LiteflowPropertyAutoConfiguration {
liteflowConfig.setPeriod(liteflowMonitorProperty.getPeriod());
liteflowConfig.setWhenMaxWorkers(property.getWhenMaxWorkers());
liteflowConfig.setWhenQueueLimit(property.getWhenQueueLimit());
liteflowConfig.setParseOnStart(property.isParseOnStart());
return liteflowConfig;
}
}

View File

@ -33,6 +33,13 @@
"sourceType": "com.yomahub.liteflow.springboot.LiteflowProperty",
"defaultValue": 512
},
{
"name": "liteflow.parse-on-start",
"type": "java.lang.Boolean",
"description": "Set whether the rule file needs to be parsed at startup.",
"sourceType": "com.yomahub.liteflow.springboot.LiteflowProperty",
"defaultValue": true
},
{
"name": "liteflow.monitor.enable-log",
"type": "java.lang.Boolean",

View File

@ -3,6 +3,7 @@ liteflow.slot-size=1024
liteflow.when-max-wait-seconds=15
liteflow.when-max-workers=4
liteflow.when-queue-limit=512
liteflow.parse-on-start=true
liteflow.monitor.enable-log=false
liteflow.monitor.queue-limit=200
liteflow.monitor.delay=300000

View File

@ -48,5 +48,6 @@ public class LiteflowConfigSpringbootTest extends BaseTest {
Assert.assertFalse(config.getEnableLog());
Assert.assertEquals(4, config.getWhenMaxWorkers().longValue());
Assert.assertEquals(512, config.getWhenQueueLimit().longValue());
Assert.assertEquals(true, config.isParseOnStart());
}
}

View File

@ -0,0 +1,38 @@
package com.yomahub.liteflow.test.flowmeta;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.LiteflowResponse;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.test.BaseTest;
import com.yomahub.liteflow.test.flowmeta.cmp2.DCmp;
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;
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/flowmeta/application.properties")
@SpringBootTest(classes = FlowMetaSpringbootTest.class)
@EnableAutoConfiguration
@ComponentScan({"com.yomahub.liteflow.test.flowmeta.cmp1"})
public class FlowMetaSpringbootTest extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
//测试自定义AOP串行场景
@Test
public void testFlowMeta() {
FlowBus.addNode("d", DCmp.class);
LiteflowResponse<DefaultSlot> response= flowExecutor.execute2Resp("chain1", "it's a request");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("a==>b==>c==>d", response.getSlot().printStep());
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,2 @@
liteflow.rule-source=flowmeta/flow.xml
liteflow.parse-on-start=false

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain1">
<then value="a,b,c,d"/>
</chain>
</flow>

View File

@ -5,5 +5,4 @@ liteflow.rule-source=config/flow.json;com.yomahub.flowtest.custom.CustomXmlClass
liteflow.when-max-wait-seconds=20
liteflow.monitor.enable-log=true
liteflow.monitor.queue-limit=300
liteflow.monitor.delay=10000
#liteflow.monitor.period=10000
liteflow.monitor.delay=10000